Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose populate ObjectID from multiple possible collections

I have a mongoose model that looks something like this

var LogSchema = new Schema({
    item: {
        type: ObjectId,
        ref: 'article',
        index:true,
    },
});

But 'item' could be referenced from multiple collections. Is it possible to do something like this?

var LogSchema = new Schema({
    item: {
        type: ObjectId,
        ref: ['article','image'],
        index:true,
    },
});

The idea being that 'item' could be a document from the 'article' collection OR the 'image' collection.

Is this possible or do i need to manually populate?

like image 482
Cade Embery Avatar asked Nov 15 '16 23:11

Cade Embery


People also ask

How do you populate with aggregate?

With the latest version of mongoose (mongoose >= 3.6), you can but it requires a second query, and using populate differently. After your aggregation, do this: Patients. populate(result, {path: "patient"}, callback);

What is Mongoose schema types ObjectId?

ObjectId . A SchemaType is just a configuration object for Mongoose. An instance of the mongoose. ObjectId SchemaType doesn't actually create MongoDB ObjectIds, it is just a configuration for a path in a schema.

How does Mongoose populate work under the hood?

Mongoose uses two queries to fulfill the request. The a collection is queried to get the docs that match the main query, and then the j collection is queried to populate the d field in the docs.


2 Answers

Question is old, but maybe someone else still looks for similar issues :)

I found in Mongoose Github issues this:

mongoose 4.x supports using refPath instead of ref:

var schema = new Schema({
  name:String,
  others: [{ value: {type:mongoose.Types.ObjectId, refPath: 'others.kind' } }, kind: String }]
})

In @CadeEmbery case it would be:

var logSchema = new Schema({
  item: {type: mongoose.Types.ObjectId, refPath: 'kind' } },
  kind: String
})

But I did't try it yet...

like image 145
Lucas Matuszewski Avatar answered Sep 23 '22 11:09

Lucas Matuszewski


First of all some basics

The ref option says mongoose which collection to get data for when you use populate().

The ref option is not mandatory, when you do not set it up, populate() require you to give dynamically a ref to him using the model option.

@example

 populate({ path: 'conversation', model: Conversation }).

Here you say to mongoose that the collection behind the ObjectId is Conversation.

It is not possible to gives populate or Schema an array of refs.

Some others Stackoverflow people asked about it.


Soluce 1: Populate both (Manual)

Try to populate one, if you have no data, populate the second.


Soluce 2: Change your schema

Create two link, and set one of them.

var LogSchema = new Schema({
    itemLink1: {
        type: ObjectId,
        ref: 'image',
        index: true,
    },
    itemLink2: {
        type: ObjectId,
        ref: 'article',
        index: true,
    },
});


LogSchema.find({})
     .populate('itemLink1')
     .populate('itemLink2')
     .exec()
like image 32
Orelsanpls Avatar answered Sep 22 '22 11:09

Orelsanpls