How to remove property of nested object from MongoDB document? - mongodb

I have a MongoDB document like this :
{
"_id": ObjectId("5589044a7019e802d3e9dbc5"),
"sessionId": LUUID("f49d4280-ced0-9246-a3c9-a63e68e1ed45"),
"teamId": LUUID("6ef7d1a8-f842-a54c-bd8c-daf6481f9cfc"),
"variableId": LUUID("59d1b512-eee2-6c4b-a5b5-dda546872f55"),
"values": {
"725400": 691.0000000000000000,
"725760": 686.0000000000000000,
"726120": 683.0000000000000000,
"726480": 681.0000000000000000,
"726840": 679.0000000000000000,
"727200": 678.0000000000000000,
"727560": 677.0000000000000000,
"727920": 676.0000000000000000
},
"variableType": 2,
"isSet": false,
"teamNumber": 2,
"simPageIds": []
}
I have a scenario that I have to delete a particular property from the "values" property of my document. for example, I want to delete value "727920" from the "values" property.
Since "Values" is not an array, I can't use $pull here. What I need is to remove
"727920" : 676.0000000000000000 from "values".
What is the right way to do that?

Use $unset as below :
db.collectionName.update({},{"$unset":{"values.727920":""}})
EDIT
For updating multiple documents use update options like :
db.collectionName.update({},{"$unset":{"values.727920":""}},{"multi":true})

You may try the following query using $unset
For single document update,
db.collectionName.update({ /* filter condition */ }, { $unset : { "ParentKey.ChildKey" : 1} })
For multiple documents update,
db.collectionName.updateMany({ /* filter condition */ }, { $unset : { "ParentKey.ChildKey" : 1} })

Related

Mongodb: update an object inside an array

I have the current mongo collection and need to find and specific id inside an array and update its value.
{
"_id" : ObjectId("111fe6813abdeb1505f5111"),
"objectIdUser" : ObjectId("111fe6813abdeb1505f5111"),
"objectIdClasses" : [
{
"objectIdClass" : ObjectId("111fe6813abdeb1505f5111")
}
],
}
I tried to use the following query but It never updates.
db.classes.findOneAndUpdate(
{
objectIdUser: ObjectId("111fe6813abdeb1505f5111"),
"objectIdClasses.objectIdClass": ObjectId('111fe6813abdeb1505f5111')
},
{
$set:
{
"objectIdClasses.$.objectIdClass": ObjectId('111fe6813abdeb1505f5111')
}
}
);
The records exists, but I always get a null value and the value is never updated.
Follow the below steps carefully;
db.<collectionName>.updateOne(filter, updateDoc, options);
the filter go defines the document you want to change, just like the find.
the updateDoc defines the new changes
the options instruct the method to create a document if no documents match the filter
Example:
I have a database of shop collection with the following data in a products collection
{ "_id" : 1, "name" : "Pen", "price" : 1.2 }
If I want to change the "price" to of "Pen" to 5.0 then:
db.products.updateOne({name: "Pen"}, {$set: {price: 5.0}}, {upsert: true});
Note: all your changes should be inside the <$set> object

Select the value from an array of hashes based on key from a single document in mongoid

I have a document in items collection like
// Document One
{
"_id" : ObjectId("556411af73616d0d822f0000"),
"visibility" : [
{
"user_id" : ObjectId("556412bb73616d0d82310000"),
"visible" : false
},
{
"user_id" : ObjectId("556412c973616d0d82320000"),
"visible" : true
}
]
},
// Some other documents
{...}
{...}
I want to get the value of visible only for "Document One" based on user_id I provide (eg. ObjectId("556412bb73616d0d82310000")).
How?
I am using mongoid 4.0.0.
Thanks.
You can do this in two ways :
1> Using $elemMatch and $ in projection as below
db.collectionName.find({"visibility":{"$elemMatch":{"user_id":ObjectId("556412bb73616d0d82310000")}}},
{"visibility.$visible":1,"_id":0})
it retunrns results as
"visibility" : [ { "user_id" : ObjectId("556412bb73616d0d82310000"), "visible" : false } ]
this return whole matching array in visibility
2> Using aggregation as below :
db.collectionName.aggregate({
"$unwind": "$visibility"
}, {
"$match": {
"visibility.user_id": ObjectId("556412bb73616d0d82310000")
}
}, {
"$project": {
"_id": 0,
"visible": "$visibility.visible"
}
})
return results as { "visible" : false }
Maybe you can try this:
db.one.find(
{"visibility.user_id": ObjectId("556412bb73616d0d82310000")},
{_id: 0, "visibility.$": 1})
In the query statementsdb.collection.find(query, projection), {"visibility.user_id": ObjectId("")} is used to select the required item, and {_id: 0, "visibility.$": 1} is used to show the specified field.
What's more, $ operator (projection) is used to limit the output to be the matched one of array.
Official Doc: http://docs.mongodb.org/manual/reference/operator/projection/positional/#projection
$
The positional $ operator limits the contents of an from the query results to contain only the first element matching the query document. To specify an array element to update, see the positional $ operator for updates.
Use $ in the projection document of the find() method or the findOne() method when you only need one particular array element in selected documents.

Casbah MongoDB, how to both add and remove values to an array in a single operation, to multiple documents?

After searching, I was unable to figure out how to perform multiple updates to a single field.
I have a document with a "tags" array field. Every document will have random tags before I begin the update. In a single operation, I want to add some tags and remove some tags.
The following update operator returns an error "Invalid modifier specified: $and"
updateOperators: { "$and" : [
{ "$addToSet" : { "tags" : { "$each" : [ "tag_1" , "tag_2"]}}},
{ "$pullAll" : { "tags" : [ "tag_2", "tag_3"]}}]}
collection.update(query, updateOperators, multi=true)
How do I both add and remove values to an array in a single operation, to multiple documents?
You don't need the $and with the update query, but you cannot update two fields at the same time with an update - as you would see if you tried the following in the shell:
db.test.update({}, { "$addToSet" : { "tags" : { "$each" : [ "tag_1" , "tag_2"]}},
"$pullAll" : { "tags" : [ "tag_2", "tag_3"] }}, true, false)
You would get a Cannot update 'tags' and 'tags' at the same time error message. So how to achieve this? Well with this schema you would need to do it in multiple operations, you could use the new bulk operation api as shown below (shell):
var bulk = db.coll.initializeOrderedBulkOp();
bulk.find({ "tags": 1 }).updateOne({ "$addToSet": { "$each" : [ "tag_1" , "tag_2"]}});
bulk.find({ "tags": 1 }).updateOne({ "$pullAll": { "tags": [ "tag_2", "tag_3"] } });
bulk.execute();
Or in Casbah with the dsl helpers:
val bulk = collection.initializeOrderedBulkOperation
bulk.find(MongoDBObject("tags" -> 1)).updateOne($addToSet("tags") $each("tag_1", tag_2"))
bulk.find(MongoDBObject("tags" -> 1)).updateOne($pullAll("tags" -> ("tags_2", "tags_3")))
bulk.execute()
Its not atomic and there is no guarantee that nothing else will try to modify, but it is as close as you will currently get.
Mongo does atomic updates so you could just construct the tags you want in the array and then replace the entire array.
I would advise against using an array to store these values all together as this is an "unbound" array of tags. Unbound arrays cause movement on disk and that causes indexes to be updated and the OS and mongo to do work.
Instead you should store each tag as a seperate document in a different collection and "bucket" them based on the _id of the related document.
Example
{_id : <_id> <key> <value>} - single docuemnt
This will allow you to query for all the tags for a single user with db.collection.find({_id : /^<_id>/}) and bucket the results.

mongodb upsert in updating an array element

Want to upsert in object properties in a array of a document
Consider a document in collection m
{ "_id" : ObjectId("524bfc39e6bed5cc5a9f3a33"),
"x" : [
{ "id":0.0, "name":"aaa"},{ "id":1.0, "name":"bbb"}
]
}
Want to add age:100 to { "id":0.0, "name":"aaa"} .
Not just age .. But but provision for upsert in the array element {}. So it can contain {age:100,"city":"amd"} (since i am getting this from the application service)
Was trying this... But did not worked as it replaced the entire array element
db.m.update({_id:ObjectId("524bfc39e6bed5cc5a9f3a33"),
"x" : {
"$elemMatch" : {
"id" : 0.0
}
}},
{
$set : {
"x.$" : {
"age": 100
}
}
},
{upsert: true}
)
Changed the document to (which i did not wanted)
{ "_id" : ObjectId("524bfc39e6bed5cc5a9f3a33"),
"x" : [
{ "age":100},{ "id":1.0, "name":"bbb"}
]
}
Is this possible without changing schema.
$set : {"x.$" : {"age": 100}}
x.$ sets the entire matched array element to {age: 100}
This should work:
db.m.update({_id:ObjectId("524bfc39e6bed5cc5a9f3a33"),
"x.id": 0.0}, {$set: {"x.$.age": 100 }});
Using elemMatch:
db.test.update({x: {$elemMatch: {id: 1}}},{$set: {"x.$.age": 44}})
Note that the upsert option here, is redundant and wouldn't work if the id isn't present in x because the positional operator $ doesn't support upserting.
This is not possible without changing schema. If you can change schema to use an object to store your items (rather than an array), you can follow the approach I outlined in this answer.

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