I am trying to make a populate query with mongodb (using mongoose as orm), and it doesn´t work 100%. I mean that I get all the entries from the document where I apply the populate... ALL, the entries that (on the crossed document) match with the match query (and I obtain a nested object), but I get the others too (and the nested object is null).
This is what I have done:
MODELS
var userSchema = Schema({
name: String,
email: String,
idiom: String
});
var ticketsSchema = Shema({
user_id:{ type:Schema.Types.ObjectId, ref:'User', required: true},
date: Date,
points: Number,
kart: String
});
POPULATE
tickets.find()
.populate(
{
path: 'user_id',
match:{name:"user1"}
}
).exec(function (err, result) {
if (err) return handleError(err);
res.send(result);
});
And a possible result could be:
Object[0]
__v: 0
_id: "5655b68ccbe953bc2a78da54"
date: "2015-11-25T13:24:28.561Z"
date: "2015-11-25T13:24:28.561Z"
points: 50
kart: "Senior"
user_id: Object
__v: 0
_company: 0
_id: "5655b656cbe953bc2a78da53"
name: "user1"
email: "user1#mail.com"
idiom: "es"
Object[1]
__v: 0
_id: "5655b732e0685c441fddb99b"
date: "2015-11-25T13:27:14.608Z"
points: 75
kart: "Pro Senior"
user_id: Object
__v: 0
_company: 0
_id: "5655b656cbe953bc2a78da53"
name: "user1"
email: "user1#mail.com"
idiom: "es"
Object[2]
__v: 0
_id: "56564613701da2981aa017d6"
date: "2015-11-25T23:36:51.774Z"
points: 75
kart: "Pro Senior"
user_id: null
Object[3]
__v: 0
_id: "565646ee701da2981aa017d8"
date: "2015-11-25T23:40:30.308Z"
points: 75
kart: "Pro Senior"
user_id: null
This isn´t exactly what I want to do... I would want that the two last doesn´t show up.
EDIT
I think I didn´t explain clear myself clearly... what I want to do is a JOIN query...
I have seen that I need use a mapreduce, I tried to do but I don´t found a place where it is explained for... dummies. All what I could do until now is this:
ticketsDB.find()
.populate(
{
path: 'user_id',
match:req.body
}
).exec(function (err, result) {
if (err) return res.send(err);
reslt=[];
for(var i in result)
if(result[i].user_id)reslt.push(result[i]);
console.log(reslt);
res.send(reslt);
});
Thank you.
Thanks #JohnnyHK by his comment, I found the solution here: Mongoose nested query on Model by field of its referenced model
And now the code is something like:
usersDB.find(req.body, function(err, docs) {
var ids = docs.map(function(doc) { return doc._id; });
ticketsDB.find({user_id: {$in: ids}})
.populate('user_id').exec(function (err, result) {
if (err) return res.send(err);
reslt=[];
for(var i in result)
if(result[i].user_id)reslt.push(result[i]);
res.send(reslt);
});
});
Where req.body is {name:"user 1"} or {email:"user1#user.com"}.
EDIT
I was thinking a little (sorry, it will happen no more ;p ), and I think that there is a way to remove the mapping of this query. Now my answer is this:
usersDB.find(req.body).distinct("_id", function(err, docs) {
ticketsDB.find({user_id: {$in: docs}})
.populate('user_id').exec(function (err, result) {
if (err) return res.send(err);
reslt=[];
for(var i in result)
if(result[i].user_id)reslt.push(result[i]);
res.send(reslt);
});
});
Could be that valid??
Related
i am trying to update or remove a subdocument from a parent document using mongoose.
My code:
editSubscription(req, res) {
const token = req.headers.authorization;
jwt.verify(token, req.app.get('yourSecretKey'), function (err, payload) {
userModel.update({ _id: payload.user._id, "subscriptions._id": req.params.id }, { "$set": { "subscriptions.$": req.body } }, function (err, obj) {
console.log(obj)
})
})
}
The output of the console.log is
{ n: 0, nModified: 0, ok: 1 }
How should i do this? i know if its modified the nModified returns a 1. I can't find any docs on how to approach this or solve it and all the solutions here on stackoverflow i already tried, nothing is working.
A sample of a document in my collection:
id: '5db990daa05aa90de0c8b86b',
user:
{ role: 'User',
subscriptions: [
{ active: true,
_id: '5dbad05aaf232e2bdc033339',
name: 'Basic Fit',
price: 20,
paymentDate: '07-11-2020',
created: '2019-10-31T12:15:22.360Z',
updated: '2019-10-31T12:15:22.360Z' },
{ active: true,
_id: '5dbad2568bf56255a0f39bc7',
name: 'Netflix',
price: 10,
paymentDate: '07-11-2019',
created: '2019-10-31T12:23:50.141Z',
updated: '2019-10-31T12:23:50.141Z' } ]
],
_id: '5db990daa05aa90de0c8b86b',
fullname: 'Test naam',
email: 'test1#mail.com',
password:
'$2a$10$VzBnIcVraIRdmzy6rPHOX.7gGOXToTBNISLEfi429OfpRx02FxCaO',
birthDate: '02-12-1988',
created: '2019-10-30T13:32:10.276Z',
updated: '2019-10-30T13:32:10.276Z',
__v: 0 },
payload.user._id == the verified logged in user ID
req.params.id is supposed to be the subscriptionId im trying to edit
Try this:
editSubscription(req, res) {
const token = req.headers.authorization;
jwt.verify(token, req.app.get('yourSecretKey'), function (err, payload) {
userModel.update({ _id: ObjectId(payload.user._id), "subscriptions._id": ObjectId(req.params.id) }, { "$set": { "subscriptions.$": req.body } }, function (err, obj) {
console.log(obj)
})
})
}
I tried and im getting a 500 error response back..
When i remove the 'req.params.id' and i do it like this:
userModel.updateOne({ _id: payload.user._id }, { "$set": { "subscriptions.0.price":
req.body.price} }).then(user => {
console.log(user)
}).catch(err => {
console.log(err)
})
Then it works but since i have multiple items in an array i do not want to update only the first one..
I tried using a filter in the $set operator but im getting errors all over the place..
Note: I asked this question here, however at that time I was working purely with MongoDB, now I am trying to implement this with Mongoose. I decided it was appropriate to ask a separate question as I believe the answer will be fundamentally different, however please let me know if I was incorrect in that decision.
I have a collection with the following format:
[
{
firstname: 'Joe',
lastname: 'Blow',
emails: [
{
email: 'test#example.com',
valid: false
},
{
email: 'test2#example.com',
valid: false
}
],
password: 'abc123',
_id: 57017e173915101e0ad5d94a
},
{
firstname: 'Johnny',
lastname: 'Doe',
emails: [
{
email: 'test3#example.com',
valid: false
}
],
password: 'abc123',
_id: 57017e173915101e0ad5d87b
},
]
I am trying to find a user based on the emails.email field. Here is what I have so far:
UserModel.find()
.where('emails')
.elemMatch(function (elem) {
elem.where('email').equals(userEmail);
})
.limit(1)
.exec(
(err, usersReturned) => {
console.log('test2#example.com');
});
What am I doing wrong? I am new to Mongoose and just can't seem to figure this out.
You could do something like this :
UserModel.find({"emails.email": userEmail}).limit(1).exec(function(err, user){
if(err) console.log("Error: " + JSON.stringify(err));
else if(user) console.log("User Returned is : " + JSON.stringify(user));
});
You can use Mongodb aggregate function .Use $unwind on "emails.email" field and it will separate the array make as independent documents.
UserModel.aggregate( [
{ $unwind : "$emails" },
{ $match: {$emails.email:"email you want to put"}}
],function(err,result){
//write code but you want to do
});
This is my schema.
team_year: String,
team: [{
_leader: String,
_member:[{
_name: String,
_phone: String,
_age: Number,
_gender: String,
_comment:[{
_date: String,
_contents: String,
_attendance: Boolean
}]
}]
}]
I have data
{ team_year: 2015
team: [
{
_leader: tom
_member: [
{_name: mike,
_phone: 2222
]
},
{
_leader:jack,
_member: []
}
]
}
I want to register a team member of Jack.
team_schema.findOneAndUpdate(
{team_year: '2015', 'team._leader' : 'jack'},
{$push: {
'team._member': req.body
}
},
function(err, post){
if (err) next(err);
res.end("success");
});
but it doesn't work.
Please help me.
I use
Node.js + express + MongoDB
I'm not good at English. T^T
You need to specify the index of the object for which you want to insert an object (nested array). For this you can use the positional operator ('$') provided by MongoDB. See here for more info.
So this query should work:
team_schema.findOneAndUpdate(
{team_year: '2015', 'team._leader' : 'jack'},
{$push: {
'team.$._member': req.body //The $ symbol resolves to an index from the query
}
},
function(err, post){
if (err) next(err);
res.end("success");
});
I try to update a document with mongoose and it fails. The query I can successful execute directly in Mongo is like:
db.orders.update(
{
orderId: 1014428,
'delivery.items.id': '5585d77c714a90fe0fc2fcb4'
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}
)
When I try to run the following update command with mongoose:
this.update(
{
orderId: this.orderId ,
"delivery.items.id": product.id
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}, function (err, raw) {
if (err) {
console.log(err);
}
console.log('The raw response from Mongo was ', raw);
}
);
I see the following error:
{ [MongoError: cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})]
name: 'MongoError',
message: 'cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})',
index: 0,
code: 16837,
errmsg: 'cannot use the part (items of delivery.items.id) to traverse the element ({items: [ { quantity: 1, price: 6.9, name: "Manipulationstechniken", brand: null, id: "5585d77c714a90fe0fc2fcb4" } ]})' }
The raw response from Mongo was { ok: 0, n: 0, nModified: 0 }
I tried so many things. Any advice on this?
As requested the schema:
var Order = new Schema({
orderId: Number,
orderDate: String,
customerName: String,
state: Number,
delivery: {
items: {type: Array, default: []},
state: { type: Number, default: 0 }
}
});
TL;DR: use your model Order instead of an instance this when doing more advanced queries:
Orders.update(
{
orderId: this.orderId ,
"delivery.items.id": product.id
},
{
$inc: {
"delivery.items.$.quantity" : 1
}
}, function (err, raw) {
if (err) {
console.log(err);
}
console.log('The raw response from Mongo was ', raw);
}
);
Explanation:
Mapping differences between Model.update() and Document.update().
The using the model, then Model.update() will be used and
Model.update(conditions, doc, options, callback)
will be mapped to:
db.collection.update(query = conditions, update = doc, options)
When using an instance instead your calling Document.update() and
Document.update(doc, options, callback)
will be mapped to the following:
db.collection.update(query = {_id: _id}, update = doc, options)
Don't know if this helps, but in this question the O.P. had a similar issue with mongoose 3.6.15, and claimed it was solved in 3.8.22
EDIT: In the linked question, the O.P. had the following working on mongodb
db.orchards.update(
({"orchardId": ObjectId("5391c137722b051908000000")},
{"trees" : { $elemMatch: {"name":"apple"}}}),
{ $push: { "trees.$.fruits": ObjectId("54c542c9d900000000001234") }})
But this not working in mongoose:
orchards.update(
({"orchardId": ObjectId.fromString(orchard.id)},
{"trees" : {$elemMatch: {"name": "apple"}}}),
{$push: {"trees.$.fruits": ObjectId("54c542c9d900000000001234") }},function(err, data){ ...
In a comment, he said the issue was solved switching to mongoose 3.8.22
I'm looking for the mongodb database to find object with value lat > 0 (latitude of user). But the result is empty.
What is the correct query? In my case {pos:{lat:{ $gte : 0 }}} is incorrect.
the code:
var userSchema = new mongoose.Schema({
name: String,
activated:{ type:Number, min:0, max:1 },
pos:{
lat:{ type:Number, min:-90. , max: 90.},
lon:{ type:Number, min:-180., max:180.}
}
});
User.find({pos:{lat:{ $gte : 0 }}},function(err, vals) {
if (err) return console.error(err);
console.dir(vals.length);//shows zero length
});
But if I'm trying to find
User.find({ activated:1 },function(err, vals) {
if (err) return console.error(err);
console.dir(vals.length);//shows correct size
});
Try to use
User.find({"pos.lat":{ $gte : 0 }}, function...