29

I'm not sure how to populate the sample schema below or if it is even possible. Can a reference be within an object like below? If you can, how would you populate it? E.g. .populate('map_data.location');?

var sampleSchema = new Schema({
  name: String,
  map_data: [{
    location: {type: Schema.Types.ObjectId, ref: 'location'},
    count: Number
  }]
});

Or will I have to have two separate arrays for location and count like so:

// Locations and counts should act as one object. They should
// Be synced together perfectly.  E.g. locations[i] correlates to counts[i]
locations: [{ type: Schema.Types.ObjectId, ref: 'location'}],
counts: [Number]

I feel like the first solution would be the best, but I'm not entirely sure how to get it working within Mongoose.

Thank you very much for any help!

Ryan Endacott
  • 8,772
  • 4
  • 27
  • 39

6 Answers6

30

The first solution is possible.

Mongoose currently has limitations (see this ticket here) populating multiple levels of embedded documents, however is very good at understanding nested paths within a single document - what you're after in this case.

Example syntax would be:

YourSchema.find().populate('map_data.location').exec(...)

Other features, such as specifying getters / setters on paths, orderBy and where clauses, etc. also accept a nested paths, like this example from the docs:

personSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});

Internally Mongoose splits the string at the dots and sorts everything out for you.

Jed Watson
  • 20,150
  • 3
  • 33
  • 43
  • As far as the second point goes: Do you have a top element? If so, give everything a top_id and a parent_id. Or descendents array and a children array. Then, take everything from top, and sort out inheritance on client side. – dansch Nov 17 '13 at 03:08
18

First option is ok, but if someone would have problems with that query map_data.location - Mongoose returns empty array instead of object - I found that this will work:

.populate({
     path: 'map_data.location',
     model: 'Location'
})
kkochanski
  • 2,178
  • 23
  • 28
  • According to the [**documentation**](https://mongoosejs.com/docs/populate.html#cross-db-populate), it seems that specifying the `model` key is only useful if you need to populate across MongoDB databases or MongoDB instances. – Chunky Chunk Aug 19 '19 at 02:16
4
   YourSchema.find()
       .populate({
            path: 'map_data',
            populate: {
                path: 'location' 
            }
    }).exec(...)

The above statement will populate array of map_data and also the location object of each map_data.

hope this helps someone.

Akash Kumar Verma
  • 3,185
  • 2
  • 16
  • 32
Otis-iDev
  • 101
  • 1
  • 4
2

i think you will need this:

if you schema is this:

var sampleSchema = new Schema({
name: String,
map_data: [{
location: {type: Schema.Types.ObjectId, ref: 'location'},
count: Number
}]
});

you monggosse query have to be:

const responseMap=await YourSchema.find()
.populate(
path: 'map_data._id',
model: 'location'
select:['nameLocation','geoPoints','count'],
).exec();
console.log(responseMap);

but you count variable have to be in location schema, and map_data have to containt only id location.

  • 1
    Welcome to StackOverflow. We usually don't recommend sending regards, thanks, or any other tagline in order to keep the content of the answer clear & concise and to adhere to the technical writing guidelines. – Bassem May 15 '20 at 22:05
1

If someone couldn't solve his/her problem I got a solution It works for me.

My Schema:

const categorySchema = new Schema(
{
    name: {
        type: String,
        unique: true
    },
    products: [{
        type: Schema.Types.ObjectId,
        ref: 'Product'
    }]
})

And then to get a category with an specific name and with their products:

.get('/:name', async (req, res) => {
const { name } = req.params;
    
    const responseMap = await Category.find({name})
            .populate({
                path: 'products',
                model: 'Product',
            })
            .exec();

    res.send(responseMap);})
0

The first option is the best. "count" is part of object "map_data".