简体   繁体   中英

How to populate a non related field mongoose

Document Role =

{ "_id" = "12345",  
   Name = "Developer"
},

{ "_id" = "67890",  
   Name = "Manager"
}

Document Employee =

{ "_id" = "00000",
  "Name"= "Jack",
  "Roles"= [{_id:"12345"},{_id:"67890"}]
}

I want to select one Role and list all the users having the same role How to do that?

I want to get some thing like.

{ "_id" = "12345",  
   Name = "Developer"
   Employees = [{"_id":"00000"}]
}

Is it possible to use populate to achieve this?

Mongoose .populate() and other methods you might find are not "join magic" for MongoDB. What they in fact all do is execute "additional" query(ies) operations on the database and "merge" the results "under the hood" for your as opposed to you doing the work yourself.

So your best option as long as you can deal with it is to use "embedding" which keeps the "related" information in the document for which you are "pairing" it to, such as for "Roles":

{
    "_id": "0000",
    "name": "Developer",
    "employees": [{ "_id": "12345", "name": "Jack" }]
}

Which is simple, but of course comes at it's own cost and dealing with the "embedded" entries and how you use it according to "updating" or "reading" as is appropriate. It's a single "read" operation, but "updates" may be more costly due to the need to update the embedded information in multiple places, and multiple documents.

If you can "live" with "referencing" and the cost it incurs then you can always do this:

var rolesSchema = Schema({
    "name": String,
    "emloyees": [{ "type": Schema.Types.ObjectId, "ref": "Employee" }]
});

var employeesSchema = Schema({
    "name": String,
    "roles": [{ "type": Schema.Types.ObjectId, "ref": "Role" }]
});

var Role = mongoose.model('Role',rolesSchema); var Employee = mongoose.model('Employee',employeeSchema);

Role.find({ "_id": "12345"}).populate("employees").exec(function(err,docs) { // populated "joined" results in here })

What this does behind the scenes is effectively (basic JavaScript representation and "at best") :

var roles = db.role.find({ "_id": "12345" }).map(function(doc) {
   doc.employees = doc.employees.map(function(employee) {
       return db.employees.find({ "_id": { "$in": doc.employees } }).toArray();
   })
})

Mongoose works on the concept of using the "schema" definition to "know" which collection to execute the "other query" on and then return the "joined" results to you. But it is not a single query but multiple hits to the database.

Other schemes might "keep" the referenced collection information in the document itself, as opposed to relying on the "model code" to get that information. But the same principle applies where you need to make another call to the database and perform some type of "merge" in the API provided.

So it all falls down to your choice. Either you "embed" the data and live with that cost, or you "reference" the data and live with the network "cost" that is associated with multiple database hits.

The key point here is "nothing is free", and not even the way that SQL RDBMS perform "joins" which also has a "cost" of it's own and is a lot of the reasoning why NoSQL solutions like MongoDB do it this way and "do not support joins" in a native fashion for the "cost" involved in distributed data systems.

The main lesson here is to "do what suits you and your application", and not just choose the "coolest thing right now", but basically expect what you get from choosing different storage solutions. They all have their own purposes. Horses for Courses as the saying goes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM