Reputation: 1348
I have two models in user.js
and userProfile.js
of mongoose, where I want to get documents using a join query but I have not take ref in user schema so I have code as below:
user.js
var userSchema = new Schema({
nick_name:{type:String},
email: {type: String},
password: {type: String},
is_active:{type:String,enum:['1','0'],default:"1"},
},{ collection: 'user'});
userProfile.js
var userProfileSchema = new Schema({
user_id:{type:Schema.Types.ObjectId, ref:'User'},
first_name:{type:String},
last_name:{type:String},
address:{type:String},
country:{type:String},
state:{type:String},
city:{type:String},
gender:{type:String,enum:['m','f','o'],default:"m"},
is_active:{type:String,enum:['1','0'],default:"1"},
},{ collection: 'userProfile'});
server.js
app.get('/api/userLists', function(req, res) {
User.find({},"nick_name email",function(err, user) {
if(err) {
res.json(err);
} else {
var userIds = user.map(function(obj){
return obj._id;
});
UserProfile.find({user_id:{$in:userIds}},function(err,userProfiles){
if(err){
res.json(userProfiles);
console.log(userProfiles);
}else{
---------------------------------
-What to do here, I have no idea.-
---------------------------------
res.json(user);
}
});
}
});
});
expected output as follows
{
"nick_name" : "laxman",
"email" : "[email protected]",
"first_name" : "my first name",
"last_name" : "my last name",
"address" : "my address",
"country" : "my country",
"state" : "my state",
"city" : "my city",
"gender" : "m",
}
**OR**
{
"nick_name" : "laxman",
"email" : "[email protected]",
"profile" :{
"first_name" : "my first name",
"last_name" : "my last name",
"address" : "my address",
"country" : "my country",
"state" : "my state",
"city" : "my city",
"gender" : "m",
}
}
dependencies
"express" => "version": "4.7.4",
"mongoose" => "version": "4.4.5",
"mongodb" => "version": "2.4.9",
"OS" => "ubuntu 14.04 lts 32bit",
Upvotes: 3
Views: 13351
Reputation: 1662
You can use aggreate which implements mongodb aggregation.
Sample code may be looked like:
UserProfile.aggregate()
.match({user_id: {$in: userIds}})
.group({_id: "$user_id"}) // '$' is must
.project(...) // fields you want from UserProfile
.exec(function(err, result){
// do populate or something
})
You may also like to know how to populate the aggregate result.
Upvotes: 1
Reputation: 48396
Please try this one, or you could use async
or promise to make codes more concisely.
MyUser.find({}, 'nick_name email', function(err, users){
if (err)
console.log(err);
else {
var len = users.length;
var curIdx = 0;
var newUsers = [];
users.forEach(function(user) {
UserProfile.findOne({user_id: user._id}, function(err, ret) {
if (err)
console.log(err);
else{
// combine those two objects here...
user.set('profile', ret.toJSON(), {strict: false})
newUsers.push(user);
++curIdx;
if (curIdx == len) {
//console.log(newUsers);
res.json(newUsers);
}
}
});
});
}
})
Upvotes: 3
Reputation: 103365
Population would be ideal in your case. From the docs:
Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s).
Population will seamlessly help you bring data from the Profile
collection into your User
model. For example, to get the second output in the json form
{
"nick_name": "laxman",
"email": "[email protected]",
"profile": {
"first_name" : "my first name",
"last_name" : "my last name",
"address" : "my address",
"country" : "my country",
"state" : "my state",
"city" : "my city",
"gender" : "m",
}
}
consider the following example with the approach you can take. Change your User
schema to
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
nick_name: { type: String },
email: { type: String },
password: { type: String },
profile: { type: Schema.Types.ObjectId, ref: 'UserProfile' }
},{ collection: 'user'});
module.exports = mongoose.model('User', userSchema);
In your user schema definition, you add the primary surrogate key to a user profile, called ObjectId
, referenced as _id
in the data to get the populate functionality. This will be the key used to refer to documents in the UserProfile
collection.
Reading the data
This is where Mongoose population displayes how very straightforward, easy and fast it is to makes reads of documents through its populate()
function. So for instance, to show the referenced profile
on a user, call the populate()
method with the name of that field in a string as a parameter e.g.
app.get('/api/userLists', function(req, res) {
User.find({}, "nick_name email")
.populate("profile")
.exec(function(err, users) {
if(err) {
res.json(err);
} else {
res.json(users)
}
});
Writing data
When you save data for the user
model, you will also need to save the references to the profile. For instance, when a new User
is created, you'll need the UserProfile _id reference saved as the profile field:
var user = new User();
var profileId = "54b5659536cd5250a3a93bd3"; // <-- user profile id, for example.
user.nick_name = req.body.name;
user.email = req.body.email;
user.password = encrypt(req.body.password, user.nick_name);
user.profile = profileId;
user.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'user created!' });
});
Upvotes: 4