There is no join in mongoose but sometimes we still want to refer to other collection document,population.
Population is the process of automatically replacing the document specified in document with another collection. We can migrate document, multiple document, simple object, multiple simple objects, or all objects returned by the query.
var Mongoose = require (' Mongoose ' ), Schema = Mongoose. Schema var personschema = schema ({_id:n Umber, Name:string, Age:number, stories: [{type:Schema.Types.ObjectId, ref: ' story ' ', title:string, fans: [{type:number, ref: ' person ' var Story = Mongoose.model (' Story ' var person = Mongoose.model (' person ', personschema);
So far we've created 2 of the model. The stories field of the person model has been set to a objectids array. The ref option tells Mongoose which model to use when population, in our case the story model. All the _id we store here must be document _id from the story Model. We also stated that the story _creator attribute is number, as is the type of _id in Personschema. It is important to match the types of _id and ref.
Note: ObjectId, number, String, and buffer can also be used as ref.
Save ref
Saving the ref for other document works the same as saving the property, just assigning the _id value.
var aaron =NewPerson ({_id:0, Name: ' Aaron ', age:100}); Aaron.save (function(err) {if(ERR)returnHandleError (ERR); varStory1 =NewStory ({title:"Once upon a Timex.", _creator:aaron._id//Assign the _id from the person }); Story1.save (function(err) {if(ERR)returnHandleError (ERR); //thats it! });});
Population
So far, we haven't done anything much different. We just created a person, a story. Now, let's take a look at using the Query Builder to populate our story ' S_creator:
' Once upon a Timex. ' }). Populate (' _creator '). EXEC (function (err, story) { if return handleError (err); Console.log (' The creator is%s ', story._creator.name); // Prints "The creator is Aaron"});
The populated paths are no longer set to the original _id, and their values will be replaced by the mongoose document returned from the database before returning the results by querying them individually.
The ref array works the same way. The populate method on the query will return a document array instead of the original _ids.
Mongoose >= 3.6 Exposes the original _ids used during population through the document#populated () method.
Setting populated Fields
In Mongoose >= 4.0, you can also populate a domain manually.
function (Error, story) { if (error) { return handleError (Error); } = Aaron; // prints "Aaron"});
Note that this is only valid for a single ref. You cannot manually populate a ref array at this time.
Field selection
What if we just want some specific fields filled with the document? This can be done by passing the General field name syntax as the second parameter to the populate method.
/timex/i}). Populate (// only return the Persons name. EXEC ( err, story ) { ifreturn handleError (err); Console.log (' The creator is%s ', story._creator.name); // Prints "The creator is Aaron" Console.log (' The creators is%s ', story._creator.age); // Prints "The creators is Null"})
Populating multiple Path
What if we want to fill more than one path at a time?
story.find (...). Populate (// separated path name with a space . EXEC ()
In Mongoose >= 3.6, we can pass a path name consisting of a space-delimited string to populate. You must execute the populate () method several times before 3.6.
story.find (...). Populate(' fans '). Populate (' _creator '). EXEC ()
Query criteria and other options
If we want to populate the fans array by age, select only their name and return up to 5 people?
story.find (...). Populate ({ ' fans ', +} }, ' name-_id ', 5 }}). EXEC ()
Refs to children
If we use the Aaron object, we cannot get the stories list. This is because no story object has been ' stacked ' to aaron.stories.
There are two points of view here. First of all, let Aaron know which stories is his.
Aaron.stories.push (Story1); Aaron.save (callback);
This enables us to perform a find and fill combination:
' Aaron ' }). Populate (///// only works if we pushed refs to children. EXEC ( Err, person) { ifreturn handleError (err); Console.log (person);})
It is debatable whether we want two sets of pointers, because they may be out of sync. Instead, we can skip filling and accurately find () the story we are interested in.
story.find ({_creator:aaron._id}). exec (function (err, stories) { if return handleError (err); Console.log (' The stories is an array: ', Stories);})
Modify ref
Now, we have a story that _creator incorrect. We can modify refs just like any other Mongoose property setting:
varGuille =NewPerson ({name: ' Guillermo ')}); Guille.save (function(err) {if(ERR)returnHandleError (ERR); Story._creator=Guille; Console.log (Story._creator.name); //prints "Guillermo" in Mongoose >= 3.6 //See https://github.com/Automattic/mongoose/wiki/3.6-release-notesStory.save (function(err) {if(ERR)returnHandleError (ERR); Story. FindOne ({title:/timex/i}). Populate ({path:' _creator ', select: ' Name '}). EXEC (function(err, story) {if(ERR)returnHandleError (ERR); Console.log (' The creator is%s ', Story._creator.name)//Prints "The creator is Guillermo" }) })})
The document returned from query population becomes a fully functional, removable, and saved document, unless the lean option is specified. To confuse them with the sub-documents . Be careful when calling its Delete method, because you will delete it from the database, not just the array.
Populate existing document
If we have an existing mongoose document and want to populate it with some path,mongoose >= 3.6 supports the Document#populate () method.
Populating multiple existing document
If we have one or more files, even simple objects (like the MapReduce output), we can populate them in Mongoose >= 3.6 using the Model.populate () method. Document#populate () and query#populate () are used to update the document in this way.
Populating across multiple levels
You have a user schema that records the users ' friends.
var New Schema ({ name:string, ' User ' }});
Padding lets you get a list of the user's friends, but what if you want a friend of the user's friend? Specify the populate option to tell Mongoose to populate the friend array with all of the user's friends:
User. ' Val ' }). Populate ({ ' friends ', // Get Friends of Friends-populate the ' friends ' Array for every friend populate: {path: ' Friends ' } });
Populating across Databases
For example, you have a Shema representing the event and a Shema representing conversation. Each event has a corresponding conversation thread.
var New Schema ({ name:string, // The ID of the corresponding conversation // Notice there ' s no ref here! Conversation:objectid}); var New Schema ({ nummessages:number});
Also, assume that the event and conversation are stored in a separate MongoDB instance.
var db1 = mongoose.createconnection (' localhost:27000/db1 '); var db2 = mongoose.createconnection (' localhost:27001/db2 '); var event = Db1.model (' event ', Eventschema); var Conversation = Db2.model (' conversation ', conversationschema);
In this case, you will not be able to populate () normally. Because populate () does not know which model,conversation domain to use is always empty. However, you can definitely specify the mode.
Event. Find (). ' Conversation ', model:conversation}). EXEC (function/** /});
This can be referred to as a "cross-database population" because it enables you to populate it through a MongoDB database or even through a MongoDB instance.
Mongoose Document (vii) Population