count of updated objects using node mongodb native client - node.js

I have the following update MongoDB query, run in Node.js via MongoDB native client. The query works correctly - I see objects being modified in my MongoDB after I run this code:
collection.update(
{
_id : request.query.person,
},
{
$inc: {
score : 1
}
},
{ safe : true},
this /* "this" is for Step */
);
I would like to know what is the number of records that were updated in MongoDB after my query. I have seen that I can do check it by running getLastError in MongoDB, but I am not sure how to do it from Node.js using the native client.
Any hints how to do it? Is there any other way than calling getLastError?

The second parameter to the update callback is the count of affected docs:
collection.update(
{ _id : request.query.person },
{ $inc: { score : 1 }},
{ safe : true},
function (err, numAffected) {
...
}
);
Update for the 2.x version of the native driver:
The second parameter to the update callback is now a nested object, where the number of documents updated can be found in result.nModified. But update is now deprecated so updateOne should be used instead.
collection.updateOne(
{ _id : request.query.person },
{ $inc: { score : 1 }},
{ safe : true},
function (err, response) {
console.log(response.result.nModified);
// Also available at response.modifiedCount for updateOne, but not update
console.log(response.modifiedCount);
}
);
The documentation for the 2.x callback parameters can be found here.

Related

How do I update data in mongo

So I am currently working on a project with mongodb and nodejs and I was wondering, how can you update data in mongodb via nodejs? My problem is that I want to keep the old data and add new. For example, here is the data currently in my mongodb
{
"_id" : ObjectId("5a1c0c1c3b147ec2e31cceb3"),
"event_id" : "1",
"event_medium" : "null",
"event_tags" : ["#JustTesting"]
}
So I want to add new data to the event_tags array and still keep the old data.
So for example the end result would be this:
{
"_id" : ObjectId("5a1c0c1c3b147ec2e31cceb3"),
"event_id" : "1",
"event_medium" : "null",
"event_tags" : ["#JustTesting", "#Test", "#Something"]
}
You should use the update function of MongoDB for that. MongoDB knows different update operators, in your case you may use $push or $pushAll (the second is deprecated):
update one after the other with $push
YourCollection.update({ _id: 'xxx' }, { $push: { event_tags: '#Test' } });
YourCollection.update({ _id: 'xxx' }, { $push: { event_tags: '#Something' } });
or both at once with $pushAll (deprecated now)
YourCollection.update({ _id: 'xxx' }, { $pushAll: { event_tags: ['#Test', '#Something'] } });
To interact with MongoDB form your NodeJS app, I would use a library like this one.
Your starting point is the Update function in CRUD (Create,Read, Update, Delete) operations in Mongodb.
Your node program should have among others the update function where you set the _id field you want to update and load the content fields to be update in 'data' for example as below:
myModel.prototype.update = function (_id, data, callback) {
const query = { _id: this.mongo.ObjectId(_id) };
debug(' update:' + JSON.stringify(query));
this.mongo.collection('mycollection').update(query, data, callback);
};
This piece of code should be put in your Model, if you use MVC pattern.
There is a lot to go.
Honestly I recommend a more deep tutorial like parts 3 and 4 of this one for nodejs and Mongoose (mongo db driver):
MDN tutorial for mongo/node/express
I assume you are using mongoose..
eventModel.findOne({event_id:1 },
function(err, eventObj){
if(err){
//handle error
} else {
if(eventObj === null) {
//event doesnot exist
}
var tagList = eventObj.event_tags;
tagList.push('new_tag1');
tagList.push('new_tag2');
eventObj.event_tags = tagList;
eventObj.save(function(err){
if(err){
//handle error
} else {
//success
}
})

FeathersJS Mongoose: Updating matched sub-document not working

I want to update a value of a sub-document where a message has a specific id and an user id is in a recipient array. I want to update a value of the matched object with the specified user id.
When I run the following query on the MongoDB CLI, everything works and the value is updated:
db.getCollection('messages').update({
_id : ObjectId("57d7edb8c497a75a6a7fde60"),
"recipients.userId" : "5789127ae2bcc79326462dbc"
},{
$set : {"recipients.$.read": true}
});
But when I run the following query via JS in my FeathersJS application:
messageService.update({
_id : '57d7edb8c497a75a6a7fde60',
"recipients.userId" : "5789127ae2bcc79326462dbc"
},{
$set: {"recipients.$.read": true}
}).then(function(e) {
console.log(e)
}).catch(function(e) {
console.log(e);
});
I get the error:
GeneralError: The positional operator did not find the match needed from the query. Unexpanded update: recipients.$.read
What am I doing wrong?
And is there a better way of updating many messages at once?
Thanks!
For updating one or multiple records by a query you need to call the service method by setting id to null and putting the query into params.query:
messageService.update(null, {
$set: {"recipients.$.read": true}
}, {
query: {
_id : '57d7edb8c497a75a6a7fde60',
"recipients.userId" : "5789127ae2bcc79326462dbc"
}
}).then(function(e) {
console.log(e)
}).catch(function(e) {
console.log(e);
});

Updating Nested subdocument using id mongoose

I need to edit my prescriptions quantity .Here is my sample code.
collection.update(
{ "_id" : 1,"medications._id" : 23,"medications.prescriptions._id":77 },
{ $set : { "medications.$0.prescriptions.$1.quantity" : 30 } },
false,
true
)
How to edit this. It does not shown any error .
Instead you can follow a more easy to understand way.
var updateData = {
medications.prescriptions.quantity: 0
}
collection.update({ "_id" : 1,"medications._id" : 23,"medications.prescriptions._id":77 }, updateData, function(err, response){
if(err){
res.json(err);
}
//your success handler
});
you can use only one positional operator
And see this documentation:
https://docs.mongodb.com/manual/reference/operator/update/positional/
I have faced the same issue for the as array inside Array update require much performance impact. So, mongo db doest not support it. Redesign your database as shown in the given link below.
https://pythonolyk.wordpress.com/2016/01/17/mongodb-update-nested-array-using-positional-operator/

How to properly do a Bulk upsert/update in MongoDB

I'm trying to:
Find a document according to a search criteria,
If found, update some attributes
If not insert a document with some attributes.
I'm using a Bulk.unOrderedOperation as I'm also performing a single insert. And I want to do everything in one operation againast DB.
However something it's causing nothing is being inserted for the update/upsert operation.
This is the insert document:
var lineUpPointsRoundRecord = {
lineupId: lineup.id, // String
totalPoints: roundPoints, // Number
teamId: lineup.team, // String
teamName: home.team.name, // String
userId: home.iduser, // String
userName: home.user.name, // String
round: lineup.matchDate.round, // Number
date: new Date()
}
This is the upsert document:
var lineUpPointsGeneralRecord = {
teamId: lineup.team, // String
teamName: home.team.name, // String
userId: home.iduser, // String
userName: home.user.name, // String
round: 0,
signupPoints: home.signupPoints, // String
lfPoints: roundPoints+home.signupPoints, // Number
roundPoints: [roundPoints] // Number
};
This is how I'm trying to upsert/update:
var batch = collection.initializeUnorderedBulkOp();
batch.insert(lineUpPointsRoundRecord);
batch.find({team: lineUpPointsRoundRecord.teamId, round: 0}).
upsert().
update({
$setOnInsert: lineUpPointsGeneralRecord,
$inc: {lfPoints: roundPoints},
$push: {roundPoints: roundPoints}
});
batch.execute(function (err, result) {
return cb(err,result);
});
Why wouldn't it be upserting/updating?
Note
That is JS code using waterline ORM which also uses mongodb native driver.
Your syntax here is basically correct, but your general execution was wrong and you should have "seperated" the "upsert" action from the other modifications. These will otherwise "clash" and produce an error when an "upsert" occurs:
LineupPointsRecord.native(function (err,collection) {
var bulk = collection.initializeOrderedBulkOp();
// Match and update only. Do not attempt upsert
bulk.find({
"teamId": lineUpPointsGeneralRecord.teamId,
"round": 0
}).updateOne({
"$inc": { "lfPoints": roundPoints },
"$push": { "roundPoints": roundPoints }
});
// Attempt upsert with $setOnInsert only
bulk.find({
"teamId": lineUpPointsGeneralRecord.teamId,
"round": 0
}).upsert().updateOne({
"$setOnInsert": lineUpPointsGeneralRecord
});
bulk.execute(function (err,updateResult) {
sails.log.debug(err,updateResult);
});
});
Make sure your sails-mongo is a latest version supporting the Bulk operations properly be the inclusion of a recent node native driver. The most recent supports the v2 driver, which is fine for this.
I recommend use bulkWrite exemplary code with bulk upsert of many documents:
In this case you will create documents with unique md5. If document exists then will be updated but no new document is created like in classical insertMany.
const collection = context.services.get("mongodb-atlas").db("master").collection("fb_posts");
return collection.bulkWrite(
posts.map(p => {
return { updateOne:
{
filter: { md5: p.md5 },
update: {$set: p},
upsert : true
}
}
}
),
{ ordered : false }
);
https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/
Typically I have always set upsert as a property on update. Also update should be able to find the record itself so no need to find it individually.
Depending on the environment the $ may or may not be necessary.
batch.update(
{team: lineUpPointsRoundRecord.teamId, round: 0},
{
$setOnInsert: lineUpPointsGeneralRecord,
$inc: {lfPoints: roundPoints},
$push: {roundPoints: roundPoints},
$upsert: true
});

Sails + Mongo + Waterline. Sort by count documents in populated collection

I have two models - User and Tag. Part of User model
module.exports = {
attributes: {
tags: {
collection: "tag",
via: "users"
}
}};
Tag model looks like
module.exports = {
attributes: {
name: {
type: 'string',
required: true
},
users: {
collection: "user",
via: "tags"
},
}};
And I need to sort tags by "users.length" (each tag can has different number of users). I tried this
Tag.find().populate('users').sort('users.length DESC').exec(function(err, tags){});
And also I tried something like this
Tag.native(function (err, collection) {
if (err) return res.serverError(err);
collection.aggregate(
[
{ $sort : { users : -1 } }
], function (err, results) {
});
});
But I had a fail. Documents are not sorted in right order. Can you help me to sort documents as I want please? I'm a new in Sails and in Mongo too. And I have no idea how I can do this.
P.S.
I use sails-mongo adapter version 0.11.2
Unfortunately, there's no way of doing this as of now.
I would suggest maintaining a count field in the Tag model itself and updating it each time a User adds or removes a Tag. Then run a normal query like you did with count as the sort key. Doing this also allows you to query faster if you just need Tag information (and not the users) since you can skip the populate() call which internally references another collection.

Resources