Is it possible to query mongodb to return array of matching document id values, without the related keys?
Please consider following 'parent' data structur:
{
"_id": ObjectId("52448e4697fb2b775cb5c3a7"),
"name": "Peter",
"children": [
{
"name": "joe"
}
]
},
{
"_id": ObjectId("52448e4697fb2b775cb5c3b6"),
"name": "Marry",
"children": [
{
"name": "joe"
}
]
}
I would to query for an array of parent _ids whose children have the name "joe"
For provided sample data, I would like the following output returned from mongo:
[ObjectId("52448e4697fb2b775cb5c3a7"), ObjectId("52448e4697fb2b775cb5c3b6")]
I know that I can query for an output like this, which also contains the keys
[{"_id": ObjectId("52448e4697fb2b775cb5c3a7")}, {"_id": ObjectId("52448e4697fb2b775cb5c3b6")}]
However I need to push above array to another document with an update operation like this:
db.statistic.update({"date": today}, {$push: {"children": [ObjectId("52448e4697fb2b775cb5c3a7"), ObjectId("52448e4697fb2b775cb5c3b6")]}}, true, false)
I would like to avoid sorting out the document structure, in case it is possible to just return an array containing the appropriate values using mongo
It should be possible by
db.coll.distinct("_id", {"children.name": "joe"})
Related
I am beginner in MongoDB and struck at a place I am trying to fetch data from nested array but is it taking so long time as data is around 50K data, also it is not much accurate data, below is schema structure please see once -
{
"_id": {
"$oid": "6001df3312ac8b33c9d26b86"
},
"City": "Los Angeles",
"State":"California",
"Details": [
{
"Name": "Shawn",
"age": "55",
"Gender": "Male",
"profession": " A science teacher with STEM",
"inDate": "2021-01-15 23:12:17",
"Cars": [
"BMW","Ford","Opel"
],
"language": "English"
},
{
"Name": "Nicole",
"age": "21",
"Gender": "Female",
"profession": "Law student",
"inDate": "2021-01-16 13:45:00",
"Cars": [
"Opel"
],
"language": "English"
}
],
"date": "2021-01-16"
}
Here I am trying to filter date with date and Details.Cars like
db.getCollection('news').find({"Details.Cars":"BMW","date":"2021-01-16"}
it is returning details of other persons too which do not have cars- BMW , Only trying to display details of person like - Shawn which have BMW or special array value and date too not - Nicole, rest should not appear but is it not happening.
Any help is appreciated. :)
A combination of $match on the top-level fields and $filter on the array elements will do what you seek.
db.foo.aggregate([
{$match: {"date":"2021-01-16"}}
,{$addFields: {"Details": {$filter: {
input: "$Details",
as: "zz",
cond: { $in: ['BMW','$$zz.Cars'] }
}}
}}
,{$match: {$expr: { $gt:[{$size:"$Details"},0] } }}
]);
Notes:
$unwind is overly expensive for what is needed here and it likely means "reassembling" the data shape later.
We use $addFields where the new field to add (Details) already exists. This effectively means "overwrite in place" and is a common idiom when filtering an array.
The second $match will eliminate docs where the date matches but not a single entry in Details.Cars is a BMW i.e. the array has been filtered down to zero length. Sometimes you want to know this info so if this is the case, do not add the final $match.
I recommend you look into using real dates i.e. ISODate instead of strings so that you can easily take advantage of MongoDB date math and date formatting functions.
Is a common mistake think that find({nested.array:value}) will return only the nested object but actually, this query return the whole object which has a nested object with desired value.
The query is returning the whole document where value BMW exists in the array Details.Cars. So, Nicole is returned too.
To solve this problem:
To get multiple elements that match the criteria you can do an aggregation stage using $unwind to separate the different objects into array and match by the criteria you want.
db.collection.aggregate([
{
"$match": { "Details.Cars": "BMW", "date": "2021-01-26" }
},
{
"$unwind": "$Details"
},
{
"$match": { "Details.Cars": "BMW" }
}
])
This query first match by the criteria to avoid $unwind over all collection.
Then $unwind to get every document and $match again to get only the documents you want.
Example here
To get only one element (for example, if you match by _id and its unique) you can use $elemMatch in this way:
db.collection.find({
"Details.Cars": "BMW",
"date": "2021-01-16"
},
{
"Details": {
"$elemMatch": {
"Cars": "BMW"
}
}
})
Example here
You can use $elemenMatch into query or projection stage. Docs here and here
Using $elemMatch into query the way is this:
db.collection.find({
"Details": {
"$elemMatch": {
"Cars": "BMW"
}
},
"date": "2021-01-16"
},
{
"Details.$": 1
})
Example here
The result is the same. In the second case you are using positional operator to return, as docs says:
The first element that matches the query condition on the array.
That is, the first element where "Cars": "BMW".
You can choose the way you want.
In Pymongo application, while iterating through every document of the collection, how to access a specific field value of the JSON structure?
{
"_id": {
"$oid": "5e1c2b0bacbdaehujjjbdsh"
},
"a": {
"data_type": "abc",
"data_format": "xyz",
"data_version": "1",
},
"b": "123",
"c": "345"
}
Based on the following code snippet, how do I access the value associated with the key 'data_format' which is nested within the key 'a' ---
for document in col.find():
data_format_val = document['a']['data_format'] # not working
Relatively new to Mongodb query commands.
It's possible that some of the documents of the collection may not have the key 'a'.
Try using $exists to make sure the field is present like this: Syntax: { field: { $exists: } }
I have got a collection of documents and each documents contains a nested array of objects.
{
"id": "309324739",
"debters": [
{
"user": {
"name": "John Doe",
"internal": true
},
"debt": 1463,
},
{
"user": {
"name": "Alex Tree",
"internal": false
},
"debt": 53443,
},
}
What I'm trying to do is to return find the document by id and then find inside the debters list that has a false flag?
I tried the following query...
Debters findByIdAndDebters_User_InternalIsFalse(#Param("id") String id,);
But I'm getting an error saying that it can find "internal" property. What am I doing wrong and how can I loop through array using this magic mongo repository query?
you need to write a native query for that which is similar to
#Query("{'debters.user.internal':false,'_id':''}")
Debters findByIdAndDebtersUserInternalIsFalse(#Param("id") String id,);
To clarify: I have a document with a subdoc. I create a new document with the same data of the other one and it gets a new id. However, when I copy the subdoc array they do not get a new id.
Are subdocs id local to the parent doc? I.e. would the following be a problem?
[
{
"__v": 1,
"_id": "5214af03a9f53efa61000004",
"name": "Foo",
"subdocs": [
{
"thing": "value",
"_id": "5214af03a9f53efa61000006"
}
]
},
{
"__v": 0,
"name": "Foo",
"_id": "5214af03a9f53efa61000014",
"subdocs": [
{
"thing": "value",
"_id": "5214af03a9f53efa61000006"
}
]
}
]
There is a unique index on the _id field of documents stored directly in a collection, but not for embedded documents, nor is there any requirement that embedded documents have an _id field at all. The two documents you have provided are both valid to be stored in MongoDB in the same database (I'm interpreting your example as an array of two documents that are both stored directly in a collection together).
I've the following entity persisted on mongo in a users collection:
{
"fullname": "Luke Tomson",
"nicknames": [
{
"name": "lukeone",
"created": ISODate("2011-05-18T19:42:56.411Z")
},
{
"name": "magicluke",
"created": ISODate("2012-01-12T19: 42: 56.411Z")
},
{
"name": "superluke",
"created": ISODate("2012-03-27T19: 42: 56.411Z")
}
}
]
}
How do I get the last nickname name for a user whose fullname is "Luke Tomson" ? And more specifically, how do I retrieve in the mongo shell a specific index (the first or the last) of a sorted array that was sorted upon a specific field (in this case, created).
Thanks
From the documentation, the second object passed to a .find is a selection of what portions of the object you want returned.
So, what you want is basically:
db.users.find({"fullname": "Luke Tomson"}, {"nicknames": { $slice: -1 } });
Though you might also want to return the _id if there are multiple "Luke Tomson"s in your DB and you need to uniquely identify them.