MongoDb - Find a specific obj within nested arrays - arrays

I hope someone can shed some light on this issue that I have, it's driving me crazy to a point that I have been spending the past three days, learning more and more about mongoDB but still can't figure out this simple query.
What I need to do is to get the object containing the "carId" = "3C".
In other words the object that I want the query to return is:
{
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
}
Here is the dataset (cars):
{
"_id" : ObjectId("56223329b64f07a40ef1c15c"),
"username" : "john",
"email" : "john#john.com",
"accounts" : [
{
"_id" : ObjectId("56322329b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "6A",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
},
{
"carId" : "6B",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
}
]
}
]
},
{
"_id" : ObjectId("56223125b64f07a40ef1c15c"),
"username" : "paul",
"email" : "paul#paul.com",
"accounts" : [
{
"_id" : ObjectId("5154729b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "5B",
"_id" : ObjectId("56323329854f07a40ef1c15e")
}
]
},
{
"_id" : ObjectId("56322117b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "6G",
"_id" : ObjectId("51212929b64f07a40ef1c15e")
},
{
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
},
{
"carId" : "4N",
"_id" : ObjectId("51241279b64f07a40ef1c15e")
}
]
}
]
}
Please note that I have two nested arrays, and apparently MongoDb lacks when it comes to dealing with Projections with deep arrays. The $ operator can only be used once in a projection; leaving with no clues as how to to achieve this simple task.
So again I want to find --only-- the document that has "carId" : "3C" and only return the immediate obj containing the "carId" : "3C". but not the parent objects.
Any help would be so much appreciated. Possibly using either direct MongoDb or Mongoose. Mongoose would be preferred.
As for reference, I have already covered these other related issues wasn't able to figure it out.
Updating a deep record in MongoDb
How to Update Multiple Array Elements in mongodb
Hope in the future, this question and your solutions will help others.

Amir,
You must use the Aggregation Framework. You can build a pipeline that processes a stream documents through several building blocks: filtering, projecting,grouping,sorting,etc.
When dealing with nested arrays you will have to use the $unwind command. You can get what you want by doing the following.
db.cars.aggregate(
//De-normalized the nested array of accounts
{"$unwind": "$accounts"},
//De-normalized the nested array of cars
{"$unwind": "$accounts.cars"},
//match carId to 3C
{"$match": {"accounts.cars.carId" : "3C"}},
//Project the accoutns.cars object only
{"$project" : {"accounts.cars" : 1}},
//Group and return only the car object
{"$group":{"_id":"$accounts.cars"}}
).pretty();
You can use the aggregation framework for "array filtering" by using $unwind .
You can delete each line from the bottom of each command in the aggregation pipeline in the above code to observe the pipelines behavior.

Here's an example without the aggregation framework. I don't think there's a way purely from querying that you'll be able to get just the individual nested object you're looking for so you have to do a little post processing work. something like Mongoose may provide a way to do this but I'm not really up on what the Mongoose API's look like currently.
var doc = db.cars.findOne({"accounts.cars" : {$elemMatch: {"carId" : "3C"}}}, {"accounts.cars.$": 1, _id: 0})
var car = doc.accounts[0].cars[0]

Related

Mongo DB find unsupported projection option

Hi everyone ı have a little problem with mongoDB find command , I'm searching for usage of it but ım trying same comand with same document model but it's just do not work on my server but ıt work on this website , can anyone explain this to me ?
web server document:
{
"_id":ObjectId("60eb509db0f1b4e8a07aaf40),
"item":"journal",
"status":"A",
"size": {
"h":14,
"w":21,
"uom" : "cm"
}
}
my code :
db.inventory.find({}, {"size": {"uom":1}}).pretty()
it gives me uoms value ,
But this is does not working on my server document:
{
"normalized": true,
"payload": {
"client_ip" : "1.1.1.1",
"dist" : "13",
"server_ip":"1.1.1.1",
"timestamp":2021/07/09 22:00:05",
"subject": "cli"
}
}
my code :
db.hpfeed.find({}, {"payload":{"client_ip":1}})
output
Error:error:{
"ok" : 0,
"errmsg" : "Unsupported projection option : payload : {client_ip: 1.0}",
"code" : 2,
"codeName" : "BadValue"
After a lot of try ı found the solution :
db.hpfeed.find({}, {"payload.client_ip":1})
You may be testing on different MongoDB versions. From the docs:
For fields in an embedded documents, you can specify the field using either:
* dot notation; e.g. "field.nestedfield":
nested form; e.g. { field: { nestedfield: } } (Starting in MongoDB 4.4)
Source

Query array of embedded mongodb documents [duplicate]

This question already has answers here:
Match multiple criteria inside an array [duplicate]
(2 answers)
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
MongoDB : find value in Array with multiple criteria
(1 answer)
Closed 3 years ago.
I am trying to query a mongodb document without luck.
The following query works to get a user whose id is domainOwner and scope is clearcrimson.
db.getCollection("users").findOne( { "roles": { $elemMatch: {_id: "domainOwner", scope: "clearcrimson" } } }, {_id:1})
How can I modify the query to get a user whose one email id could be a#b.com, id is domainOwner and scope is clearcrimson?
Document:
{
"_id" : "7Rc5q2o3Qnv7j2HuT",
"emails" : [
{"address" : "a#b.com"},
{"address" : "c#d.com"},
],
"roles" : [
{"_id" : "domainOwner", "scope" : "clearcrimson"},
{"_id" : "domainOwner", "scope" : "clearcrimson2"}
]
}
db.getCollection("users").findOne({ "roles": {$elemMatch: { "_id": "domainOwner", "scope": "clearcrimson"}}, "emails.address": "a#b.com" })
As you are using $elemMatch to match multiple conditions in a single object of the array, you can use simple arrayName.fieldName to match for a single condition, like I did with "emails.address" in query above.
You can use $ (positional operator to project only matched object from array)
db.getCollection("users").findOne({ "roles": {$elemMatch: { "_id": "domainOwner", "scope": "clearcrimson"}}, "emails.address": "a#b.com" }, {_id: 1, "roles.$": 1, emails: 1})
We can not use two positional operators in one projection stage.
I am using mongo version 3.4.

Error E QUERY [thread1] SyntaxError: invalid property id #(shell) using and/or with find()

I am getting the error while using this query
db.a.find({$or:[{"name" : "aekansh"},{"age" : 21}]}).pretty()
as
E QUERY [thread1] SyntaxError: invalid property id #(shell):1:11
collection a stores the data as
{ "_id" : 10, "name" : "aekansh" }
{ "_id" : 11, "name" : "ram" }
{ "_id" : ObjectId("59dda15e153802c1d1cf8500"), "name" : "ramu" }
{ "_id" : 12, "nm" : "raj", "age" : 21 }
{ "_id" : ObjectId("59dda1d26b740896d9f067a3"), "nm" : "rj", "age" : 22, "bfff" : "yes" }
{ "_id" : ObjectId("59dda1ea11fc6ddeb8784f7e"), "nm" : "rj1", "age" : 22, "bfff" : "yes" }
I have looked at syntax and I think it is right. Why I am getting the error. Thanx in advance.
Edit- I am using online terminal for MongoDb https://www.jdoodle.com/online-mongodb-terminal
As was mentioned before your query is correct.
If fails on this online terminal it means terminal is buggy.
You have in fact 3 solutions about which I know:
Install MongoDB on your local computer and use MongoDB Compass or MongoShell to query your database.
Use Mongo Web Shell which is accessible on MongoDB documentation site.
The last option is to set up free cluster from Mongo site. They give you for free some space in cloud, set up database for you and as in first option you can use MongoDB Compass or MongoShell to query it from you local computer.

MongoDB: updating an array in array

I seem to be having an issue accessing the contents of an array nested within an array in a mongodb document. I have no problems accessing the first array "groups" with a query like the following...
db.orgs.update({_id: org_id, "groups._id": group_id} , {$set: {"groups.$.name": "new_name"}});
Where I run into trouble is when I try to modify properties of an element in the array "features" nested within the "group" array.
Here is what an example document looks like
{
"_id" : "v5y8nggzpja5Pa7YS",
"name" : "Example",
"display_name" : "EX1",
"groups" : [
{
"_id" : "s86CbNBdqJnQ5NWaB",
"name" : "Group1",
"display_name" : "G1",
"features" : [
{
_id : "bNQ5Bs8BWqJn6CdNa"
type : "blog",
name : "[blog name]"
owner_id : "ga5YgvP5yza7pj8nS"
},
]
},
]
},
And this is the query I tried to use.
db.orgs.update({_id: "v5y8nggzpja5Pa7YS", "groups._id": "qBX3KDrtMeJGvZWXZ", "groups.features._id":"bNQ5Bs8BWqJn6CdNa" }, {$set: {"groups.$.features.$.name":"New Blog Name"}});
It returns with an error message:
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 2,
"errmsg" : "Too many positional (i.e. '$') elements found in path 'groups.$.features.$.name'"
}
})
It seems that mongo doesn't support modifying arrays nested within arrays via the positional element?
Is there a way to modify this array without taking the entire thing out, modifying it, and then putting it back in? With multiple nesting like this is it standard practice to create a new collection? (Even though the data is only ever needed when the parent data is necessary) Should I change the document structure so that the second nested array is an object, and access it via key? (Where the key is an integer value that can act as an "_id")
groups.$.features.[KEY].name
What is considered the "correct" way to do this?
After some more research, it looks like the only way to modify the array within an array would be with some outside logic to find the index of the element I want to change. Doing this would require every change to have a find query to locate the index, and then an update query to modify the array. This doesn't seem like the best way.
Link to a 2010 JIRA case requesting multiple positional elements...
Since I will always know the ID of the feature, I have opted to revise my document structure.
{
"_id" : "v5y8nggzpja5Pa7YS",
"name" : "Example",
"display_name" : "EX1",
"groups" : [
{
"_id" : "s86CbNBdqJnQ5NWaB",
"name" : "Group1",
"display_name" : "G1",
"features" : {
"1" : {
type : "blog",
name : "[blog name]"
owner_id : "ga5YgvP5yza7pj8nS"
},
}
},
]
},
With the new structure, changes can be made in the following manner:
db.orgs.update({_id: "v5y8nggzpja5Pa7YS", "groups._id": "s86CbNBdqJnQ5NWaB"}, {$set: {"groups.$.features.1.name":"Blog Test 1"}});

MongoDB - Using Aggregate to get more than one Matching Object in an Array

I'm trying to do exactly what the poster in this link was trying to accomplish. I have documents with the same structure as the poster; in my documents there is an array of objects, each with many keys. I want to bring back all objects (not just the first, as you can with an $elemMatch) in that array where a key's value matches my query. I want my query's result to simply be an array of objects, where there is a key in each object that matches my query. For example, in the case of the linked question, I would want to return an array of objects where "class":"s2". I would want returned:
"FilterMetric" : [
{
"min" : "0.00",
"max" : "16.83",
"avg" : "0.00",
"class" : "s2"
},
{
"min" : "0.00",
"max" : "16.83",
"avg" : "0.00",
"class" : "s2"
}
]
I tried all the queries in the answer. The first two queries bring back an empty array in robomongo. In the shell, the command does nothing and return me to the next line. Here's a screenshot of robomongo:
On the third query in the answer, I get an unexpected token for the line where "input" is.
I'm using MongoDB version 3.0.2. It appears as if the OP was successful with the answer, so I'm wondering if there is a version issue, or if I'm approaching this the wrong way.
The only problem with the answers in that question seems to be that they're using the wrong casing for FilterMetric. For example, this works:
db.sample.aggregate([
{ "$match": { "FilterMetric.class": "s2" } },
{ "$unwind": "$FilterMetric" },
{ "$match": { "FilterMetric.class": "s2" } },
{ "$group": {
"_id": "$_id",
"FilterMetric": { "$push": "$FilterMetric" }
}}
])

Resources