Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Populating different properties WITH different Models in a Mongoose Map Type Schema #10584

Closed
silvergravel opened this issue Aug 19, 2021 · 4 comments
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary

Comments

@silvergravel
Copy link

Do you want to request a feature or report a bug?
Feature Request. I guess.

What is the current behavior?
Okay so there seems to be very little about populating Mongoose Map type schema except for the $* selector, but my use case is slightly different:

So I have a schema :

Tags  = {

  taggedResources : {
    type: Map,
    of : {
      collectionId: String,
      data: [ { _id : ObjectId } ]
    }
  }

}

Now, the data captured via this schema would look something like:

taggedResources : {
  collectionid_1 : {
     collectionId : collectionId_1,
     data: [ 
       { _id : id_1 }, 
       { _id : id_2 },
     ]
  },
  collectionid_2 : {
     collectionId : collectionId_2,
     data: [ 
       { _id : id_1 }, 
       { _id : id_2 },
     ]
  }
}

Now the problem is:

I need to populate the ids in the map property collectionId_1 with the collectionId_1 model & I need to populate the ids in the map property collectionId_2 with the collectionId_2 model

So now, what I tried:

tags.populate({
  path: 'taggedResources.$*.data._id,
  model: 'collectionId_1'
})

this works, but only populates the _ids inside of collectionId_1.

I also tried this:

for (const key of tag.taggedResources.keys()) {

  tags.populate({
    path: 'taggedResources.$*.data._id,
    match: { 'taggedResources.$*.data.collectionId' : key },
    model: 'collectionId_1'
  })

}

doesn't work at all.

I also tried populating by defining a path explicitly: path: taggedResources.collectionId_1.data._id

doesn't work.

Can anyone help me with this? Is there even a way? Or will I just have to change my data model back to an array or object.

The reason why I didn't want to use a Object without any clear property definition was because, I wanted to have a more defined 'shape' to the data and stricter type checking. That was the only reason why I thought I should use Map...

Anyway, please help! This issue with Map Schema Type has been bothering me for a while now.

Nodejs version : 12
mongoose version : 5.10.2

If the current behavior is a bug, please provide the steps to reproduce.

What is the expected behavior?

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

@usernamedoesntexist
Copy link

image
hi i want to remove object that have categorie: null after populating how to do that without filter in exec?

@IslandRhythms
Copy link
Collaborator

@usernamedoesntexist please open a new issue

@IslandRhythms IslandRhythms added the help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary label Aug 19, 2021
@vkarpov15
Copy link
Collaborator

@silvergravel you'd need to set a ref in your schema. The below code populates each entry in the map based on the corresponding modelId, but it unfortunately requires Mongoose 6.0.0-rc1. It won't work in Mongoose 5.x because it requires the change from #8469 .

'use strict';
  
const mongoose = require('mongoose');

const { Schema } = mongoose;

run().catch(err => console.log(err));

async function run() {
  await mongoose.connect('mongodb://localhost:27017/test');

  await mongoose.connection.dropDatabase();

  const Person = mongoose.model('Person', Schema({ name: String }));
  const Book = mongoose.model('Book', Schema({ title: String }));

  const schema = new Schema({
    myMap: {
      type: Map,
      of: {
        modelId: String,
        data: [{
          _id: {
            type: mongoose.ObjectId,
            ref: doc => doc.parent().modelId // <-- use `modelId` as the name of the model used to populate this subdoc
          }
        }]
      }
    }
  });
  const Test = mongoose.model('Test', schema);

  const people = await Person.create({ name: 'John' });
  const book = await Book.create({ title: 'Intro to CS' });

  await Test.create({
    myMap: {
      key1: { modelId: 'Person', data: [{ _id: people._id }] },
      key2: { modelId: 'Book', data: [{ _id: book._id }] }
    }
  });

  const res = await Test.findOne().populate('myMap.$*.data._id');
  console.log(require('util').inspect(res.myMap.values(), { depth: 10, colors: true }));
}

Does this help?

@silvergravel
Copy link
Author

@vkarpov15 thank you! This should do it for me i guess.

vkarpov15 added a commit that referenced this issue Aug 24, 2021
vkarpov15 added a commit that referenced this issue Aug 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary
Projects
None yet
Development

No branches or pull requests

4 participants