How can we achieve "Select For Update" in Mongodb? - mongodb

Below is my sample document. I wanted to load this document & read total_comments value & perform certain logic on it and update the document again with new total_comments value. How should I ensure total_comments value is not updated by some other request before I complete my above explained steps?
{ "_id" : ObjectId("56782a933d5c6ca02100002b"), "total_comments" : 12, "time_updated" : 1450715963 }
In mysql, we can do it by doing "select for update"?. How can we achieve this in Mongodb?.
Here is my MongoDB version:
> db.version()
3.0.7
Here is my storage engine details:
> db.serverStatus().storageEngine
{ "name" : "mmapv1" }

Use findAndModify() to update a document.
For example you can increment total_comments by 1 with
db.collection.findAndModify({
_id: ObjectId("56782a933d5c6ca02100002b")
}, {}, {
$inc: { "total_comments": 1 }
});

Related

mongoDB updateOne not updating a record

I am trying to update a record in mongoDB using updateOne, the un updating record is in array, and all fields are updating except one field which is country, I have tried to update it using MongoChef (a GUI of MongoDB for linux), but it doesn't work, also If I update one the Document using Edit in GUI then that record is ready to update after that.
I have tried with the following query in MongoChef
db.institutions.updateOne({
"campus": { "$elemMatch": { "_id": ObjectId("578500ef87e4c326183e520e")} },
"_id": ObjectId("57f25706762c06cb7d9422fc")
},
{
"$set" : { "campus.$.country" : "SS1"
}
});
Only country field is not updating If I update any other field it works fine.
The document structure is listed under
{
"_id" : ObjectId("57f26824762c06cb7d982e37"),
"campus" : [
{
"_id" : ObjectId("578500ee87e4c326183e5201"),
"country" : "GB",
"coreId" : NumberInt(1),
"city" : "Norwich",
}
]
}
Thanks in advance any help is appreciatiable
try this query
db.institutions.updateOne(
{
"campus._id": ObjectId("578500ef87e4c326183e520e"),
"_id": ObjectId("57f25706762c06cb7d9422fc")
},
{
"$set" : { "campus.$.country" : "SS1"}
}
);
N.B: if use mongodb driver or mongoose then no need to use ObjectId("") just use "578500ef87e4c326183e520e"

mongodb update field a to be value of field b

I am trying to run a mongo query to update the value of one field with the value of another field. I have the following documents:
{ "_id" : ObjectId("56e0a3a2d59feaa43fba49d5"), "old" : 16, "new" : 17 }
{ "_id" : ObjectId("56e0a3a2d59feaa43fba49d3"), "old" : 11, "new" : 12 }
I would like to make it look like this after update:
{ "_id" : ObjectId("56e0a3a2d59feaa43fba49d5"), "old" : 16, "new" : 16 }
{ "_id" : ObjectId("56e0a3a2d59feaa43fba49d3"), "old" : 11, "new" : 11 }
I've tried the following with no luck
db.runCommand(
{
findAndModify: "testData",
query: { $where: "this.new != this.old" },
update: { old : this.new },
upsert: true
}
)
and
db.testData.update( { $where: "this.new != this.old" }, { $set: { old: this.new } } );
Is this even possible with mongoDb?
I would like to do it in a single query and not iterate through each document.
Any ideas would be greatly appreciated.
Thank you
You can try something like this and probably change _id when you want to update other document:
db.testData.find().forEach(function(elem) {
db.testData.update({
"_id": "56e0a3a2d59feaa43fba49d5"
}, {
$set: {
new: elem.old
}
});
});
You can't do that in MongoDB yet (note to visitors from the future: I'm referring to V3.2).
You have to iterate on the documents.
NB there's a trick in case you don't mind deleting the old field: use rename to rename old to new.
NB2 for some SQLike-fu actions (not this one) the aggregation framework can be useful.

Meteor/MongoDB order by

I have the following schema
{
"_id" : "PbSkep5Auv9ZBeEyR",
"item" : "Footage",
"permalink" : "footage",
"itemIndex" : 23,
}
When I paste them in my remote DB it order them by _id, which seems to be a automatic meteor key. I am using robomongo and am trying to reorder the items by 'itemIndex'. How do I do this?
robomongo or other UI have nothing to do with the order of the data: you need to specify this in your query.
lookup the Mongo documentation:
db.collection.find({}).sort( { itemIndex: -1 } )
or
db.collection.find( { $query: {}, $orderby: { itemIndex : -1 } } )
http://docs.mongodb.org/v3.0/reference/operator/meta/orderby/

MongoDB aggregation $out step: store data in another database

I'm building a new big data project and we are using MongoDB as operational database. We use Pentaho Kettle to run the ETL that processes and cleans de data.
In a step of this ETL we make a MongoDB aggregation pipeline with the next operators in this order:
{$unwind: '$metrics'},
{$match:{'metrics.event.name': 'Hover',
'observationTime':{
$gte:{
$date:"${DATA}"
}
}
}
},
{ $project : { '_id': 0,
'remoteLocation':1,
"remoteIP":1,
"language" : 1,
"observationTime" : 1,
"device" : 1,
"session_ID" : 1,
"user_ID" : 1,
"metrics" : 1,
}
},
{ $out: "Hover_tmp"}
My problem is that this query is executed over a replica database, so I cannot write there and that's what $out does in the final step.
A posible solution would be specify a collection of another non-replica MongoDB database.
Is that posible ?
Do you find any other solution?

MongoDB Update for array of object

I am having following document in mongodb
{
"_id" : ObjectId("521aff65e4b06121b688f076"),
"uuid" : "160597270101684",
sessionId" : "160597270101684.1",
"stamps" :
{
"currentVisit" : "1377500985",
"lastVisit" : "1377500985"
},
visits : [
{
"page":"google.com",
"method": "GET"
}
]
}
Requirement:
If uuid and sessionId is not present i will insert the document as above otherwise i have to push only the object to visits array.
Any help will be greatful.
MongoDB supports an upsert option on update that updates the matching document if it exists, and inserts a new document if it doesn't exist. In MongoDB 2.4+ you can use the $setOnInsert operator to further tweak this to set certain fields only if the upsert performs an insert.
db.test.update({
uuid: "160597270101684",
sessionId: "160597270101684.1"
}, {
$setOnInsert: {
stamps: {
currentVisit: "1377500985",
lastVisit: "1377500985"
}
},
$push:{
visits: {
page: "google.com",
method: "GET"
}
}
}, { upsert:true })
So in the above example, the $push to visits will always occur but the $setOnInsert to stamps will only occur if the matching document doesn't already exist.
You can achieve this by following upsert query:
db.session.update({"uuid" : "160597270101684", sessionId : "160597270101684.1"},
{$set:"stamps" :{"currentVisit" : "1377500985","lastVisit" : "1377500985"}},
$push :{visits:{"page":"yahoo.com","method": "POST"}}},
{upsert:true})
You can use $addToSet instead of $push if you want to avoid duplicates