I am trying to update a row in Mongo DB .
I have a collection named users
db.users.find()
{ "_id" : ObjectId("50e2efe968caee13be412413"), "username" : "sss", "age" : 32 }
I am trying to update the row with the username as Erinamodobo and modify the age to 55
I have tried the below way , but its not working .
db.users.update({ "_id": "50e2efe968caee13be412413" }, { $set: { "username": "Erinamodobo" } });
Please let me know where i am making the mistake ??
Pass in the _id as an ObjectId if you're using the mongo shell, otherwise, it won't find the existing user.
db.users.update({"_id": ObjectId("50e2efe968caee13be412413")},
{ "$set" :
{ "username": "Erinamodobo", "age" : "55" }})
With this query you are updating the name itself.
Notice that the syntax of an update is the following:
db.COLLECTION.update( {query}, {update}, {options} )
where query selects the record to update and update specify the value of the field to update.
So, in your case the correct command is:
db.users.update({ "name": "Erinamodobo" }, { $set: { "age": 55 } });
However, I suggets you to read the mongodb documentation, is very well written (http://docs.mongodb.org/manual/applications/update/)
As an extension to #WiredPrairie, even though he states the right answer he doesn't really explain.
The OjbectId is not a string, it is actually a Object so to search by that Object you must supply an Ojbect of the same type, i.e. here an ObjectId:
db.users.update({ "_id": ObjectId("50e2efe968caee13be412413") }, { $set: { "username": "Erinamodobo" } });
The same goes for any specific BSON type you use from Date to NumberLong you will need to wrap the parameters in Objects of the type.
Related
First time using MongoDB and I'm having an issue that I would appreciate some help with please.
Let's say I have a collection called "students" with documents in the collection structured as followed:
{
"_id": ObjectId("12345"),
"Name": "Joe Bloggs",
"Class_Grade": "b"
"Homework_Grade": "c",
}
I want to create an embedded document called "Grades" that contains the class and homework grade fields and applies this to every document in the collection to end up with:
{
"_id": ObjectId("12345"),
"Name": "Joe Bloggs",
"Class_Grade": "b"
"Homework_Grade": "c",
"Grades": {
"Class_Grade": "b",
"Homework_Grade": "c",
}
}
I have been trying to achieve this using updateMany() in MongoShell:
db.students.updateMany({}, {$set: {Grades: {"Class_Grade": $Class_Grade, "Homework_Grade": $Homework_grade"}}})
However, in doing so, I receive Reference Error: $Class_Grade is not defined. I have tried amending the reference to $students.Class_Grade and receive the same error.
Your advice would be greatly appreciated
There are a few mistakes in your query,
if you want to use the internal existing field's value, you need to use an update with aggregation pipeline starting from MongoDB 4.2, you need to wrap the update part in attay bracket [], as i added query.
use quotation in field name that you want to use from internal field ex: "$Class_Grade"
you have used field $Homework_grade, and in your documents it is G is capital in Grade so try to use exact field name $Homework_Grade
db.students.updateMany({},
[
{
$set: {
Grades: {
"Class_Grade": "$Class_Grade",
"Homework_Grade": "$Homework_Grade"
}
}
}
])
Playground
I'm in the process of updating some legacy software that is still running on Mongo 2.4. The first step is to upgrade to the latest 2.6 then go from there.
Running the db.upgradeCheckAllDBs(); gives us the DollarPrefixedFieldName: $id is not valid for storage. errors and indeed we have some older records with legacy $id, $ref fields. We have a number of collections that look something like this:
{
"_id" : "1",
"someRef" : {"$id" : "42", "$ref" : "someRef"}
},
{
"_id" : "2",
"someRef" : DBRef("someRef", "42")
},
{
"_id" : "3",
"someRef" : DBRef("someRef", "42")
},
{
"_id" : "4",
"someRef" : {"$id" : "42", "$ref" : "someRef"}
}
I want to script this to convert the older {"$id" : "42", "$ref" : "someRef"} objects to DBRef("someRef", "42") objects but leave the existing DBRef objects untouched. Unfortunately, I haven't been able to differentiate between the two types of objects.
Using typeof and $type simply say they are objects.
Both have $id and $ref fields.
In our groovy console when you pull one of the old ones back and one of the new ones getClass() returns DBRef for both.
We have about 80k records with this legacy format out of millions of total records. I'd hate to have to brute force it and modify every record whether it needs it or not.
This script will do what I need it to do but the find() will basically return all the records in the collection.
var cursor = db.someCollection.find({"someRef.$id" : {$exists: true}});
while(cursor.hasNext()) {
var rec = cursor.next();
db.someCollection.update({"_id": rec._id}, {$set: {"someRef": DBRef(rec.someRef.$ref, rec.someRef.$id)}});
}
Is there another way that I am missing that can be used to find only the offending records?
Update
As described in the accepted answer the order matters which made all the difference. The script we went with that corrected our data:
var cursor = db.someCollection.find(
{
$where: "function() { return this.someRef != null &&
Object.keys(this.someRef)[0] == '$id'; }"
}
);
while(cursor.hasNext()) {
var rec = cursor.next();
db.someCollection.update(
{"_id": rec._id},
{$set: {"someRef": DBRef(rec.someRef.$ref, rec.someRef.$id)}}
);
}
We did have a collection with a larger number of records that needed to be corrected where the connection timed out. We just ran the script again and it got through the remaining records.
There's probably a better way to do this. I would be interested in hearing about a better approach. For now, this problem is solved.
DBRef is a client side thing. http://docs.mongodb.org/manual/reference/database-references/#dbrefs says it pretty clear:
The order of fields in the DBRef matters, and you must use the above sequence when using a DBRef.
The drivers benefit from the fact that order of fields in BSON is consistent to recognise DBRef, so you can do the same:
db.someCollection.find({ $expr: {
$let: {
vars: {firstKey: { $arrayElemAt: [ { $objectToArray: "$someRef" }, 0] } },
in: { $eq: [{ $substr: [ "$$firstKey.k", 1, 2 ] } , "id"]}
}
} } )
will return objects where order of the fields doesn't match driver's expectation.
While trying to update a MongoDB document using Mongoose, can I use a findById() with a save() in the callback, or should I stick with traditional update methods such as findByIdAndModify, findOneAndModify, update(), etc.? Say I want to update the name field of the following document (please see a more elaborate example in the edit at the end, which motivated my question):
{
"_id": ObjectId("123"),
"name": "Development"
}
(Mongoose model name for the collection is Category)
I could do this:
Category.update({ "_id" : "123" }, { "name" : "Software Development" }, { new: true })
or I could do this:
Category.findById("123", function(err, category) {
if (err) throw err;
category.name = "Software Development";
category.save();
});
For more elaborate examples, it feels easier to manipulate a JavaScript object that can simply be saved, as opposed to devising a relatively complex update document for the .update() operation. Am I missing something fundamentally important?
Edited 7/21/2016 Responding to the comment from #Cameron, I think a better example is warranted:
{
"_id": ObjectId("123"),
"roles": [{
"roleId": ObjectId("1234"),
"name": "Leader"
}, {
"roleId": ObjectId("1235"),
"name": "Moderator"
}, {
"roleId": ObjectId("1236"),
"name": "Arbitrator"
}]
}
What I am trying to do is remove some roles as well as add some roles in the roles array of sub-documents in a single operation. To add role sub-documents, $push can be used and to remove role sub-documents, $pull is used. But if I did something like this:
Person.update({
"_id": "123"
}, {
$pull : {
"roles" : {
"roleId" : {
$in : [ "1235", "1236" ]
}
}
},
$push : {
"roles" : {
$each: [{
"roleId" : ObjectId("1237"),
"name" : "Developer"
}]
}
}
}
When I try to execute this, I get the error Cannot update 'roles' and 'roles' at the same time, of course. That's when I felt it is easier to find a document, manipulate it any way I want and then save it. In that scenario, I don't know if there is really any other choice for updating the document.
I typically like to use findById() when I am performing more elaborate updates and don't think you are missing anything fundamentally important.
However one method to be aware of in mongoose is findByIdAndUpdate(), this issues a mongodb findAndModify update command and would allow you to perform your first example with the following code: Category.findByIdAndUpdate("123", function(err, savedDoc) {...}).
{
"_id" : ObjectId("550add7ee0b4b54a3e7ad53c"),
"day" : "14-03-2015",
"node" : "2G",
"nodeName" : "BLR_SGSN",
"" : {
"A" : 905.84,
"B" : 261.34,
"C" : 2103.94,
"D" : 39.67
}
}
I have this as my data in mongo.
How do I get values of A,B,C,D. ??
You cannot query on this as the sub-document fields cannot be selected.
This can only be a result of a programming error doing something like this ( and probably trying to compute a key name in the process ):
db.collection.insert({
"": {
"A": 1,
"B": 2,
"C": 3
}
})
So you cannot get to sub-elements by standard query ways like:
db.collection.find({ ".A": 905.84 })
You can fix this by updating the documents in the collection affected in this way by giving them a proper key name. But it is of course this is an iterative process. Not sure how to fix this other than with JavaScript from the shell due to the naming problem but:
db.collection.find({ "": { "$exists": true } }).forEach(function(doc) {
if ( doc.hasOwnProperty("") ) {
doc.newprop = doc[""];
delete doc[""];
db.collection.update({ "_id": doc._id }, doc );
}
})
Then at least you can access things by the new "newprop" key ( or whatever you call it ):
db.collection.find({ "newprop.A": 905.84 })
And the same sort of thing will work in other drivers.
My advice here is "go and fix this" and find out the code that caused this key name to be blank in the first place.
There should be a bug report submitted to the MongoDB core project as none of the dirvers handle this well. I thought I could even use $rename here, but you can't.
So blank "" keys are a problem that needs to be fixed.
I want update an _id field of one document. I know it's not really good practice. But for some technical reason, I need to update it.
If I try to update it I get:
db.clients.update({ _id: ObjectId("123")}, { $set: { _id: ObjectId("456")}})
Performing an update on the path '_id' would modify the immutable field '_id'
And the update is rejected. How I can update it?
You cannot update it. You'll have to save the document using a new _id, and then remove the old document.
// store the document in a variable
doc = db.clients.findOne({_id: ObjectId("4cc45467c55f4d2d2a000002")})
// set a new _id on the document
doc._id = ObjectId("4c8a331bda76c559ef000004")
// insert the document, using the new _id
db.clients.insert(doc)
// remove the document with the old _id
db.clients.remove({_id: ObjectId("4cc45467c55f4d2d2a000002")})
To do it for your whole collection you can also use a loop (based on Niels example):
db.status.find().forEach(function(doc){
doc._id=doc.UserId; db.status_new.insert(doc);
});
db.status_new.renameCollection("status", true);
In this case UserId was the new ID I wanted to use
In case, you want to rename _id in same collection (for instance, if you want to prefix some _ids):
db.someCollection.find().snapshot().forEach(function(doc) {
if (doc._id.indexOf("2019:") != 0) {
print("Processing: " + doc._id);
var oldDocId = doc._id;
doc._id = "2019:" + doc._id;
db.someCollection.insert(doc);
db.someCollection.remove({_id: oldDocId});
}
});
if (doc._id.indexOf("2019:") != 0) {... needed to prevent infinite loop, since forEach picks the inserted docs, even throught .snapshot() method used.
Here I have a solution that avoid multiple requests, for loops and old document removal.
You can easily create a new idea manually using something like:_id:ObjectId()
But knowing Mongo will automatically assign an _id if missing, you can use aggregate to create a $project containing all the fields of your document, but omit the field _id. You can then save it with $out
So if your document is:
{
"_id":ObjectId("5b5ed345cfbce6787588e480"),
"title": "foo",
"description": "bar"
}
Then your query will be:
db.getCollection('myCollection').aggregate([
{$match:
{_id: ObjectId("5b5ed345cfbce6787588e480")}
}
{$project:
{
title: '$title',
description: '$description'
}
},
{$out: 'myCollection'}
])
You can also create a new document from MongoDB compass or using command and set the specific _id value that you want.
As a very small improvement to the above answers i would suggest using
let doc1 = {... doc};
then
db.dyn_user_metricFormulaDefinitions.deleteOne({_id: doc._id});
This way we don't need to create extra variable to hold old _id.
Slightly modified example of #Florent Arlandis above where we insert _id from a different field in a document:
> db.coll.insertOne({ "_id": 1, "item": { "product": { "id": 11 } }, "source": "Good Store" })
{ "acknowledged" : true, "insertedId" : 1 }
> db.coll.aggregate( [ { $set: { _id : "$item.product.id" }}, { $out: "coll" } ]) // inserting _id you want for the current collection
> db.coll.find() // check that _id is changed
{ "_id" : 11, "item" : { "product" : { "id" : 11 } }, "source" : "Good Store" }
Do not use $match filter + $out as in #Florent Arlandis's answer since $out fully remove data in collection before inserting aggregate result, so effectively you will loose all data that don't match to $match filter