MongoDB/Mongoose $inc subdocument does not modify anything - node.js

I am trying to update a subdocument inside of an array.
{
"_id" : ObjectId("5a7a017e0aa5311d9c75c86b"),
"campaignId" : "5a7a017e0aa5311d9c75c86b",
"subCampaigns" : [
{
"_id" : ObjectId("5a7a0eee6849f507d0499a18"),
"name" : "test5",
"campaignId" : ObjectId("5a7a017e0aa5311d9c75c86b"),
"subCampaignId" : "1aKysewspn6CqNGVkv6pyL"
}
{
"name" : "test8",
"amountRaised" : 20.0,
"campaignId" : ObjectId("5a7a017e0aa5311d9c75c86b"),
"subCampaignId" : "5a7a153fe035de396c6f5b3c",
"_id" : ObjectId("5a7a153fe035de396c6f5b3c")
}
],
"name" : "test8",
"__v" : 12,
"totalDonated" : 110.0
}
When I run:
db.getCollection('campaigns').update({"_id": ObjectId("5a7a017e0aa5311d9c75c86b"), "subCampaigns.subCampaignId":"5a7a153fe035de396c6f5b3c"}, {$inc: {"subCampaigns.$.amountRaised": 10}})
In the mongo console it updates the sub document fine. But when I run this in my Mongoose code:
this.campaignModel.update(
{ campaignId: '5a7a017e0aa5311d9c75c86b', 'subCampaigns.subCampaignId': '5a7a153fe035de396c6f5b3c' },
{ $inc: { 'subCampaigns.$.amountRaised': 10}},
(err: any, subResult: any) => {...
The sub document does not have its amountRaised field incremented. From what I can tell they should be identical calls?
If I run an inc at the level higher:
this.campaignModel.findOneAndUpdate(
{campaignId: object.campaignId},
{$inc: {totalDonated: donationAmount}},
() => {...
It works fine, so this must have something to do with the sub document?
I have been playing around with multiple mongoose calls for most of the day but cannot seem to get it to update correctly.

Related

$pull is not working for array in mongoose (MongoDB)

In mongoDB (Through mongoose), I am trying to remove an element in array of a collection and using $pull operator for that, but it is not working.
Rooms collection in mongoDB
{
"_id":"sampleObjectId",
"users": ["email1#example.com", "email2#example.com"]
}
Backend code to remove a user (mongoose using Node.js)
Rooms.update(
{ _id: "sampleRoomId" },
{
$pull: {
users: "email1#exmple.com" }
},
}
)
Noting happens to collection on running this code, no change happens. code runs with no errors and in output it says "nModified":0 .
I have no idea how to remove a user from collection.
//actual code output from the mongo shell. This is working as expected. check if you given //correct value in object_id query parameter.
> db.rooms.find();
{ "_id" : "sampleObjectId", "users" : [ "email1#example.com", "email2#example.com" ] }
> db.rooms.update(
... {_id: "sampleObjectId"},
... {$pull:{users:"email1#example.com"}}
... );
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.rooms.find();
{ "_id" : "sampleObjectId", "users" : [ "email2#example.com" ] }
> db.version();
4.2.6
>

how to find data in array key name nodejs from mongodb

how to find data from mongodb in nodejs i have below query but its return null, i want to find data in child_categories array Key name child_categoryname please help me i am very thanful to you
i am using nodejs i want to find 'truck repair' and in response i want to get child_categoryhrs in response related to truck repair
example = 4
JobCategories.findOne({ child_categories : { child_categoryname : 'truck repair'} })
.exec().then(result => { console.log(result); })
.catch(handleError(res));
//mongodb
{
"_id" : ObjectId("58cea64cfd70bb1aa472ef2c"),
"category_name" : "Repairing",
"date_updated" : ISODate("2017-03-20T12:04:16.323Z"),
"child_categories" : [
{
"child_categoryname" : "truck repair",
"child_categoryhrs" : 4,
"_id" : ObjectId("58cea64cfd70bb1aa472ef2d")
},
{
"child_categoryname" : "car repair",
"child_categoryhrs" : 8,
"_id" : ObjectId("58cfc5405895461b286238fa")
}
],
"__v" : 0
}

$addToSet in a nested Array item

Considering the following
User collection & sample User document
{
"_id" : ObjectId("575c01f7b8e5999addeb598c"),
"username" : "test.1#gmail.com",
"password" : "<password>",
"firstName" : "Test,
"lastName" : "User"
}
I am trying to run an update request to add an entry in userData.eventData which is meant to be an array
In mongo script I can do
> db.Users.update({_id: ObjectId("575c01f7b8e5999addeb598c")}, {"$addToSet":{"userData.eventData":"My event"}} )
And I have the following result : userData is created as an Object and eventData as a nested Array
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.Users.find({_id: ObjectId("575c01f7b8e5999addeb598c")})
{ "_id" : ObjectId("575c01f7b8e5999addeb598c"), "username" : "test.1#gmail.com", "password" : "<password>", "firstName" : "Test", "lastName" : "User", "userData" : { "eventData" : [ "My event" ] } }
While running the same logic in mongo (using driver version 2.1.21)
// with a properly initialized db object
db.collection("Users").update({"_id" : ObjectId("575c01f7b8e5999addeb598c")}, {"$addToSet": { "userData.eventData": "My Event"}}, function(err, result) {
// do something
});
I receive the following response
result:Object
n:0
nModified:0
ok:1
And indeed the database entry is unchanged.
Is that the way it is meant to behave? I can easily fix this by creating the userData.eventData array but I found disturbing the fact that node's Mongo driver and mongo shell didn't behave the same on this
Thanks in advance for your help & advice
Edit 13/6/16
Mistake was on my side, I missed a 'new' before 'ObjectId(...' in node. With it, it behaves exactly the same as in mongo shell (i.e. 'userData' is created as an Object and it includes 'eventData' array)
No issue, then :)
Update, updates an already existing object in your document.
What you want is insert or use upset which creates a new document when no document matches the query criteria
db.collection.update(
{ name: "Andy" },
{
name: "Andy",
rating: 1,
score: 1
},
{ upsert: true }
);
If you wanted to add an object to your array, you would need $push
// Insert a document in the capped collection
function push (db, collection, search, data, callback) {
db.collection(collection).update(
search, {
$push: data
}, function (err, result) {
console.log("New object pushed");
callback(err);
});
}

Nodejs Mongoose find query has slow performance

I am having an issue when performing find queries in nodejs with mongoose. While using mongo shell client, for the same query, i get a response in 2-10ms. But when i run that same query with Mongoose i get a response in 400-550ms. I've tried the mongodb driver also, but got same results.
First of all. Laptop specs are as follows: 2 CPU's and 4GB DDR3 RAM. I'm not sure what i am missing here.
mongoose.connect(config.database, function (err) {
if (err) return console.error(err);
console.log('Connected');
var startTime = Date.now();
UserModel.find().lean().exec()
.then(function (docs) {
console.log('Found ' + docs.length + ' documents');
console.log('Finished after ' + (Date.now() - startTime) + 'ms')
mongoose.connection.close();
})
.catch(function (err) {
console.err(err)
});
});
Result:
Connected
Found 2317 documents
Finished after 456ms
Shell:
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2317,
"executionTimeMillis" : 9,
"totalKeysExamined" : 0,
"totalDocsExamined" : 2317,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [ ]
},
"nReturned" : 2317,
"executionTimeMillisEstimate" : 10,
Update
When limited to 100 on both, i get the following results:
Shell: 0ms
Nodejs: ~70ms
Update
This is an example of the document structure. I have not added it before since it is not complex.
{
"_id" : ObjectId("56e6cfda713e98cc1191cae0"),
"email" : "doppelganger113#gmail.com",
"password" : "$2a$10$egjew7mBQtKMgVbK6uXV5uD1hO8yQZ1tU5nztmVZQ4nfhLovOKN2q",
"firstName" : "Marko",
"lastName" : "Kovacevicc",
"index" : 20100140,
"gender" : "Male",
"role" : "SuperAdmin",
"isActive" : true,
"__v" : 0,
"avatar" : {
"small" : "http://localhost:3000/uploads/avatar/3a8ed7bb-4f60-4f69-b8fc-372d1db9b044.png",
"medium" : "http://localhost:3000/uploads/avatar/246c6067-403d-4e47-9e65-828cfab66d84.png",
"source" : "http://localhost:3000/uploads/avatar/01dbb51c-c957-4f67-ba36-9e8cc227168c.png"
},
"birthDate" : ISODate("1991-11-28T23:00:00Z")
}
Will test this on a server instead locally just to check if it's to the laptop. But still, those searches appear to take a lot of time, which bugs me. I know they are not the same, but i did not expect this much of a difference.Also i accidentally added mongoose debug, it was tested with and without it.
Update
Shell command: db.users.find({}).explain("executionStats")

Fetch sub-document Mongodb only match with criteria

I have data in mongodb like this:
{
"_id" : ObjectId("55a12bf6ea1956ef37fe4247"),
"tempat_lahir" : "Paris",
"tanggal_lahir" : ISODate("1985-07-10T17:00:00.000Z"),
"gender" : true,
"family" : [
{
"nama" : "Robert Deniro",
"tempat_lahir" : "Bandung",
"tanggal_lahir" : ISODate("2015-07-09T17:00:00.000Z"),
"pekerjaan" : "IRT",
"hubungan" : "XXX",
"tanggungan" : false,
"_id" : ObjectId("55a180f398c9925299cb6e90"),
"meta" : {
"created_at" : ISODate("2015-07-11T20:59:25.242Z"),
"created_ip" : "127.0.0.1",
"modified_at" : ISODate("2015-07-12T15:54:39.682Z"),
"modified_ip" : "127.0.0.1"
}
},
{
"nama" : "Josh Groban",
"tempat_lahir" : "Jakarta",
"tanggal_lahir" : ISODate("2015-06-30T17:00:00.000Z"),
"pekerjaan" : "Balita",
"hubungan" : "Lain-Lain",
"tanggungan" : true,
"_id" : ObjectId("55a29293c65b144716ca65b2"),
"meta" : {
"created_at" : ISODate("2015-07-12T16:15:15.675Z"),
"created_ip" : "127.0.0.1"
}
}
]
}
when i try to find data in sub-document, with this code:
person.findOne({ _id: req.params.person, {'family.nama': new RegExp('robert', 'gi') }}, function(err, data){
// render code here
});
It show all data in Family Data,
Can we fetch or display a data only match with criteria/keyword, for example only "Robert Deniro" row
Thank You
In 'regular' MongoDB, you can use the $ operator for that. I'm not sure if it works with Mongoose, but it's worth a try:
person.findOne({
_id : req.params.person,
'family.nama' : new RegExp('robert', 'gi')
}, {
// Only include the subdocument(s) that matched the query.
'family.$' : 1
}, function(err, data){
// render code here
});
If you need any of the properties from the parent document (tempat_lahir, tanggal_lahir or gender; _id will always be included), you need to add them to the projection object explicitly.
One caveat: the $ operator will only return the first matching document from the array. If you need it to return multiple documents, you can't use this method and (AFAIK) have to postprocess the results after they are returned from the database.
It solved with this code:
var options = {
family: {
$elemMatch: { nama: req.query.keyword }
},
};
person.findOne({ _id: req.params.person, 'family.nama': keyword }, options, function(err, data){
//render code here
});
Thanks to #hassansin & #robertklep

Resources