mongodb update field a to be value of field b - mongodb

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.

Related

MongoDB - change values from one ENUM type to another

I have MongoDB entries which looks like this:
{
"_id" : ObjectId("57288862e4b05f37bc6ab91b"),
"_class" : "mydomain.ScheduleAbsenceContainer",
"containerStart" : ISODate("2016-04-06T07:30:00Z"),
"containerEnd" : ISODate("2016-04-06T10:00:00Z"),
"scheduleIntervalContainerAbsenceType" : "SCHOOL",
"scheduleIntervalContainers" : [
{
"_id" : null,
"marker" : 6,
"containerType" : "SCHOOL",
}
]
}
and I will change all scheduleIntervalContainerAbsenceType from SCHOOL to SPARE_TIME and also all containerType's from SCHOOL to SPARE_TIME.
Is there a simple possibility to do this?
Below code does what you want. It updates all the documents which has the "SCHOOL" value for "scheduleIntervalContainerAbsenceType" keys.
db.collection_name.find({"scheduleIntervalContainerAbsenceType" : "SCHOOL"})
.forEach(function (doc) {
doc.scheduleIntervalContainers.forEach(function (sch) {
if (sch.containerType === "SCHOOL") {
sch.containerType="SPARE_TIME";
}
});
doc.scheduleIntervalContainerAbsenceType="SPARE_TIME";
db.collection_name.save(doc);
});
If you want to update all the documents without checking "scheduleIntervalContainerAbsenceType" value (still updating it to "SPARE_TIME") change your query like that.
db.collection_name.find({})
.forEach(function (doc) {
doc.scheduleIntervalContainers.forEach(function (sch) {
if (sch.containerType === "SCHOOL") {
sch.containerType="SPARE_TIME";
}
});
doc.scheduleIntervalContainerAbsenceType="SPARE_TIME";
db.collection_name.save(doc);
});

Combine mongo $push and $currentDate to include time in new array element

I am trying to add a new document to a mongo array and I require one of the fields to be the current timestamp. This is for field level versioning but I can't figure out how to combine $push and $currentDate to get the result I would like.
Can someone point me in the right direction?
db.tmp.adviceReportingJourney.update(
{ _id : "5525f99be4b041151d51386e5525f99be4b041151d513870" },
{
$push: {
"$currentDate": {
"Conversation1MeetingCreated" : {
"vid" : 4,
"ts" : {"$type": "timestamp"},
"data" : 1428552213559
}
}
}
}
)
You can use your coding language date.Now to add the current time ;-)
Like (i asume java;-)):
db.tmp.adviceReportingJourney.update(
{ _id : "5525f99be4b041151d51386e5525f99be4b041151d513870" },
{
$push: {
"$currentDate": {
"Conversation1MeetingCreated" : {
"vid" : 4,
"ts" : {"$type": "timestamp"},
"data" : Date.now()
}
}
}
}
)
UPDATE: When running mongo > 3.0 you could use $currentDate. From the documentation $currentDate it shows that $currentDate only works on db.collection.update(), db.collection.findAndModify().
See the example below to update the embedded document "Conversation1MeetingCreated" (where you update the timestamp) use:
{
$currentDate: {
"Conversation1MeetingCreated.ts": { $type: "timestamp" }
},
$set: {
"Conversation1MeetingCreated.vid" : 4,
"Conversation1MeetingCreated.data": 1428552213559
}
}
Hope it helps.

db.collection.find returns multiple records after addToSet

I use addToSet command (to add UpdatedData):
MyTable.update({ "UrlLink": "http://www.someurl.com"}, {
$addToSet: {
UpdatedData: {
TheDate: ThisDate,
NewInfo: ThisInfo
}
}
},
function (err, result) {
next(err,result)
}
);
But then, when I do the query (after UpdatedData is added to my document), I see that it returns two documents. Instead of only one updated document:
db.MyTable.find( {"UrlLink": "http://www.someurl.com"})
{ "_id" : ObjectId("56485922143a886f66c2f8bb"), "UrlLink" : "http://www.someurl.com", "Stuff" : "One", "UpdatedData" : [ { "TheDate" : "11/15/2015", "NewInfo" : "Info1", "_id" : ObjectId("5648599a71efc79c660f76d3") } ] }
{ "_id" : ObjectId("5648599f71efc79c660f76d4"), "UrlLink" : "http://www.someurl.com", "Stuff": "One", "UpdatedData" : [ ] }
So it seems that addToSet creates a new document with new _id, instead of updating the old record (ObjectId("5648599f71efc79c660f76d4")). But I only see the updated document in robomongo (ObjectId("56485922143a886f66c2f8bb")). Any ideas why this happens and how I could prevent that behaviour?
update cannot create a new document, it can only update existing.
This looks like you have created two documents with the same url.. Then when you update it just updates the first one..
To prevent the creation of a document with an already existent url you can create an index and set it to unique
db.collection.createIndex({ UrlLink: 1 }, { unique: true })
This will prevent creation of new documents with the same url, and it will also make queries by UrlLink as fast as possible.

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 update and/or change an array key without using the value

I'm having trouble removing/renaming an array object from my mongodb.
{
"_id" : ObjectId("556a7e1b7f0a6a8f27e01b8a"),
"accountid" : "AC654164545",
"sites" :[
{ "site_id" : "example1.com" },
{ "002" : "example2.com" },
{ "003" : "example3.com" },
{ "004" : "example4.com" },
{ "005" : "example5.com" },
{ "006" : "example6.com" }
]}
}
Please take notice of the array key "site_id", I want to change it to "001" by either removing and appending it, which I know how to do, or rename it.
I've tried:
db.accounts.update({'id':ObjectId("556a7e1b7f0a6a8f27e01b8a")}, {$unset: {sites.site_id}})
But that says "unexpected token".
So I tried:
db.accounts.update({'id':ObjectId("556a7e1b7f0a6a8f27e01b8a")}, {$unset: {sites:site_id}})
That says "site_id is not defined"
Then I tried:
db.accounts.update({'id':ObjectId("556a7e1b7f0a6a8f27e01b8a")}, {$unset: {sites:'site_id'}})
That says WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
I also tried a $rename command:
db.accounts.update( { _id:ObjectId("556a7e1b7f0a6a8f27e01b8a") }, { $rename: { "sites.site_id": "sites.001" } } )
But that gave me a "Cannot use part (sites of sites.site_id) to traverse the element"
One option would be to use .find(), iterate through and delete it. Save the undeleted ones into an object, and run an .insert() command, but I want to stay away from that if I have too.
This site talks about dynamic renaming: http://docs.mongodb.org/manual/reference/operator/update/positional/
Aka first you make a matching query and then you use the $ to match that to the index in the array.
Here's the query that'll accomplish what you want for the test data you provided:
db.accounts.update({'accountid':"AC654164545", "sites.site_id": "example1.com"}, {$set: {"sites.$": {'001': 'example1.com'}}})
It is not recommended to use dynamic values such as numbers as a key in document structure. This will be more difficult to query using such values.
You can use $set and $elemMatch to get result as following:
db.collection.update({
'_id': ObjectId("556a7e1b7f0a6a8f27e01b8a"),
"sites": {
$elemMatch: {
"site_id": "example1.com"
}
}
}, {
$set: {
"sites.$":{"001": "example1.com"}
}
})