How to find mongoDB object by ObjectID w/MongoDB Shell? - mongodb

How can I do this in the MongoDB shell?
https://stackoverflow.com/a/14315888/8887398
Basically I'm trying to find objects by their ObjectId. All are failing so I assume it's trying to compare to string. I'm doing this directly in the MongoDB shell. Here's what I've tried:
db.myTestDB.find( {_id: 3254ummx213u5k815mn2v2 })
Result: SyntaxError: identifier starts immediately after numeric literal
db.myTestDB.find( {_id: "3254ummx213u5k815mn2v2" })
Result: Nothing
db.myTestDB.find( { "_id": "3254ummx213u5k815mn2v2" })
Result: Nothing
db.myTestDB.find( {_id: ObjectId("3254ummx213u5k815mn2v2") })
Result: Nothing
I just put a random ID in there for my examples, but I've verified the ID exists, and by looking on MongoDB Compass.

From the docs, you construct an ObjectId by using the new keyword. For example:
db.myTestDB.find( {_id: new ObjectId("3254ummx213u5k815mn2v2") })
So, you were on the right track with the last attempt in your question, you were only missing the new keyword.
Here's a more complete example. Given the following docs:
db.getCollection('X').find({})
{
"_id" : ObjectId("59d0ada3c26584cd8b79fc51"),
"name" : "A"
}
{
"_id" : ObjectId("59d0adafc26584cd8b79fc54"),
"name" : "B"
}
{
"_id" : ObjectId("59d0b2b4c26584cd8b79fd7c"),
"name" : "C"
}
This shell command will load one of those docs, by id:
db.getCollection('X').find({_id: new ObjectId("59d0ada3c26584cd8b79fc51")})
{
"_id" : ObjectId("59d0ada3c26584cd8b79fc51"),
"name" : "A"
}

Related

How to update document field with reference field value?

Actually have 2 documents: Histories and Subsidiaries, but I forgot add to Histories the subsidiary name.
Histories Document:
{
"_id" : ObjectId("59480f91ba4d070b882ff924"),
"subsidiary" : ObjectId("5947fdf3ba4d070b882ff851"),
"campaignTitle" : "Prueba Autoredeeem",
"campaignId" : ObjectId("5948004fba4d070b882ff886"),
}
Subsidiary Document
{
"_id" : ObjectId("5947fdf3ba4d070b882ff851"),
"loginId" : 50174,
"name" : "Sucursal Alpha",
}
Now I need update History Document, add a "subsidiaryName" field with "Subsidiary.name" value from Subsidiary Document
This is my first aproach:
db.getCollection('couponredeemhistories')
.updateMany({}, {$set: {subsidiaryName:
db.getCollection('subsidiaries')
.findOne({"_id": ObjectId('5947fdf3ba4d070b882ff851')}, {_id: 0,name: 1})}})
But, the result gives me an Object inside subsidiaryName, instead flat text.
{
"_id" : ObjectId("59480f91ba4d070b882ff924"),
"subsidiary" : ObjectId("5947fdf3ba4d070b882ff851"),
"campaignDescription" : "",
"campaignTitle" : "Prueba Autoredeeem",
"campaignId" : ObjectId("5948004fba4d070b882ff886"),
"subsidiaryName" : {
"name" : "Sucursal Alpha"
}
}
Then, I have 2 problems:
How to set only flat text value to subsidiaryName field?
R: Add .name to project for get flat text
How to set .findOne() "id" param for current document instead ObjectId('HARD CODE')?
R: Iterate with forEach Cursor
IMPORTANT LIMITS: this is for MongoDB Shell (MongoDB 3.4)
Thank you, please support me for fix any language issues on this question.
Updated Answers thanks to #Astro:
db.getCollection('couponredeemhistories').find()
.forEach(function(doc){
if(doc.subsidiary !== undefined){
doc.subsidiaryName = db.getCollection('subsidiaries').findOne({'_id': doc.subsidiary}, {_id: 0, name: 1}).name;
db.getCollection('couponredeemhistories').save(doc);
}
})
Try this:
db.getCollection('couponredeemhistories')
.updateMany({}, {$set: {subsidiaryName:
db.getCollection('subsidiaries')
.findOne({"_id": ObjectId('5947fdf3ba4d070b882ff851')}, {_id: 0,name: 1}).name}})

MongoDB filter array element in a nested object

I have a document as follows:
{
"_id" : ObjectId("56423b2558cb340599108b35"),
"test" : {
"source" : [
{
"member" : "abc"
},
{
"member" : "xyz"
}
]
}
}
I want to filter on the array element xyz, and I am trying the following query:
db.coll.find({ "test.source.member" : "xyz" }, { "test.source.$.member" : true }).pretty()
Apparently it used to work on 2.4, on 2.6 it does not work,
On 2.4 it returned the "xyz", whereas on 2.6 it returns "abc" i.e. the first element. Is there a way to filter "abc" because eventually i want to update. BTW, i also tried with $elemMatch and it seems to give the same output "abc".
Thanks.
According to the Docs, if you are running 2.6, this should give you the correct output:
db.coll.find({ "test.source.member" : "xyz"}, { "test.source.$" : 1}).pretty()
You could extract the member by doing this:
var member = db.coll.find(
{ "test.source.member" : "xyz"},
{ "test.source.$" : 1}
).test.source[0].member;
The value of member would be:
xyz

Meteor/Mongo nested arrays update

I'm new to meteor/mongo/js as a stack and I'm getting lost in JSON arrays and referencing them. Based another SO answer ( and the docs) I think I am close...
A document in the Orders collection, the document has nested arrays.
Order -> orderLines -> lineItems:
Sample doc:
{
"_id" : "27tGpRtMWYqPpFkDN",
"orderLines" : [
{
"lineId" : 1,
"name" : "Cheese & Pickle",
"instructions" : "",
"lineItems" : [
{
"name" : "Cheddar Cheese",
"quantity" : 1
},
{
"name" : "Branston Pickle",
"quantity" : 1
},
{
"name" : "Focaccia Roll",
"quantity" : 1
}
]
}
]
}
What I'm trying to do from the meteor/mongo shell:
Add "instructions" of "foo" to orderLines where lineId = 1
Put a new item on lineItems array
This appears to hang...
meteor:PRIMARY> db.orders.update({_id:"27tGpRtMWYqPpFkDN","orderLines.lineId":"1", {$set: {"orderLines.$.instructions":"foo"}})
...
This doesn't like the identifier in the query
meteor:PRIMARY> db.orders.update({_id:"27tGpRtMWYqPpFkDN", "orderLines.lineId":"1"}, {$push:{"orderLines.$.lineItems":" { "name" : "butter", "quantity" : 1}"}});
2015-10-27T16:09:54.489+0100 SyntaxError: Unexpected identifier
Thanks all for your comments... but I found out some answers, posted for reference
Item 1 - using $set on a value within an array
This was failing due to two typos, one missing closing } at the end of the query, second was quoting the value "1" for itemId in the query.
This works:
db.orders.update({_id:"27tGpRtMWYqPpFkDN", orderLines.lineId":1},
{$set: {"orderLines.$.instructions":"foo"}})
I also realised that when I said "It appears to hang" it is the cli waiting for a valid statement, so hints at a missing } or )!
Item 2 - using $push to add data to an array - 2 levels nested
This was failing due to quoting around the array data
db.orders.update({_id:"27tGpRtMWYqPpFkDN", "orderLines.lineId":1 },
{$push:{"orderLines.$.lineItems": { "name" : "butter", "quantity" : 1} }})
Nested Arrays: can use $ positional operator
What I want to do next is use $set on an item in the second level array, and this would require using the $ positional operator twice:
db.orders.update({"orderLines.lineId":1, lineItems.name:"Cheddar Cheese"},
{$set: {"orderLines.$.lineItems.$.quantity": 2}})
This throws an error:
Too many positional (i.e. '$') elements found in path
There is an open MongoDB enhancement request for this but it's been open since 2010
$push adds a new element to an array. You're merely trying to set the value of a particular key in an array element.
Try:
db.orders.update({ _id: "27tGpRtMWYqPpFkDN", "orderLines.lineId": 1},
{ $set: { "orderlines.$.instructions": "foo" }})
docs

MongoDB querying to with changing values for key

Im trying to get back into Mongodb and Ive come across something that I cant figure out.
I have this data structure
> db.ratings.find().pretty()
{
"_id" : ObjectId("55881e43424cbb1817137b33"),
"e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
"type" : "like",
"time" : 1434984003156,
"u_id" : ObjectId("55817c072e48b4b60cf366a7")
}
{
"_id" : ObjectId("55893be1e6a796c0198e65d3"),
"e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
"type" : "dislike",
"time" : 1435057121808,
"u_id" : ObjectId("55817c072e48b4b60cf366a7")
}
{
"_id" : ObjectId("55893c21e6a796c0198e65d4"),
"e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
"type" : "null",
"time" : 1435057185089,
"u_id" : ObjectId("55817c072e48b4b60cf366a7")
}
What I want to be able to do is count the documents that have either a like or dislike leaving the "null" out of the count. So I should have a count of 2. I tried to go about it like this whereby I set the query to both fields:
db.ratings.find({e_id: ObjectId("5565e106cd7a763b2732ad7c")}, {type: "like", type: "dislike"})
But this just prints out all three documents. Is there any reason?
If its glaringly obvious im sorry pulling out my hair at the moment.
Use the following db.collection.count() method which returns the count of documents that would match a find() query:
db.ratings.count({
"e_id": ObjectId("5565e106cd7a763b2732ad7c"),
type: {
"$in": ["like", "dislike"]
}
})
The db.collection.count() method is equivalent to the db.collection.find(query).count() construct. Your query selection criteria above can be interpreted as:
Get me the count of all documents which have the e_id field values as ObjectId("5565e106cd7a763b2732ad7c") AND the type field which has either value "like" or "dislike", as depicted by the $in operator that selects the documents where the value of a field equals any value in the specified array.
db.ratings.find({e_id: ObjectId("5565e106cd7a763b2732ad7c")},
{type: "like", type: "dislike"})
But this just prints out all three
documents. Is there any reason? If its glaringly obvious im sorry
pulling out my hair at the moment.
The second argument here is the projection used by the find method . It specifies fields that should be included -- regardless of their value. Normally, you specify a boolean value of 1 or true to include the field. Obviously, MongoDB accepts other values as true.
If you only need to count documents, you should issue a count command:
> db.runCommand({count: 'collection',
query: { "e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
type: { $in: ["like", "dislike"]}}
})
{ "n" : 2, "ok" : 1 }
Please note the Mongo Shell provides the count helper for that:
> db.collection.find({ "e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
type: { $in: ["like", "dislike"]}}).count()
2
That being said, to quote the documentation, using the count command "can result in an inaccurate count if orphaned documents exist or if a chunk migration is in progress." To avoid that, you might prefer using the aggregation framework:
> db.collection.aggregate([
{ $match: { "e_id" : ObjectId("5565e106cd7a763b2732ad7c"),
type: { $in: ["like", "dislike"]}}},
{ $group: { _id: null, n: { $sum: 1 }}}
])
{ "_id" : null, "n" : 2 }
This query should solve your problem
db.ratings.find({$or : [{"type": "like"}, {"type": "dislike"}]}).count()

Yet another MongoDB findAndModify

Please consider the following document, a part of the Runtime collection:
{
"entity_id" : 10,
"features" : [
{
"10" : "Test System 2"
},
{
"20" : "System 2 Description"
},
{
"180" : ISODate("2013-12-25T18:19:40.589Z")
},
{
"190" : ISODate("2013-12-25T18:19:40.589Z")
}
],
"_id" : ObjectId("52bb21bc8a2ebdc01c000001")
}
My goal is to update the value of the element of the "features" array having the key "20".
Here are the things I've tried (in mongo shell):
db.Runtime.findAndModify({ "query" : {"_id": "52bb21bc8a2ebdc01c000001"}, "update" : {$set : {"features.$.20":"Updated Description"}}} );
db.Runtime.findAndModify({ "query" : {"_id": "52bb21bc8a2ebdc01c000001"}, "update" : {$set : {"features['20']":"Updated Description"}}} );
db.Runtime.findAndModify({ "query" : {"_id": "52bb21bc8a2ebdc01c000001"}, "update" : {$set : {"features[1]":"Updated Description"}}} );
In all instances the shell prints
null
and nothing happens to the data. So, the main question is, of course, what is wrong with my code snippets. Also, how that "null" is supposed to get interpreted? And is there such a thing as mongo shell's log where one could find any clues? Many thanks for your help!
When using the $ positional operator in an update, your query needs to include a term that matches the element of the array you're updating:
db.Runtime.findAndModify({
query: {_id: ObjectId("52bb21bc8a2ebdc01c000001"),
'features.20': {$exists: true}},
update: {$set: {"features.$.20":"Updated Description"}}
})
Note that you also need to call ObjectId on your _id string to turn it into an actual ObjectId or it won't match the doc.