MongoDB query help: $elemMatch in nested objects - mongodb

> db.test.insert({"a" : { "b" : { "c" : { "d1" : [ "e1" ],
"d2" : [ "e2" ],
"d3" : [ "e3", "e4" ],
"d4" : [ "e5", "e6" ] } } } })
> db.test.find({'a.b.c' : {$exists : true}})
{ "_id" : ObjectId("4daf2ccd697ebaacb10976ec"), "a" : { "b" : { "c" : { "d1" : [ "e1" ], "d2" : [ "e2" ], "d3" : [ "e3", "e4" ], "d4" : [ "e5", "e6" ] } } } }
But none of these work:
> db.test.find({'a.b': "c"})
> db.test.find({'a.b': {$elemMatch : {"c" : {$exists: true}}}})
> db.test.find({'a.b': {$elemMatch : {$elemMatch : {$all : ["e1"] }}}})
Suppose I don't know what the values of c and d1...d4 are. Is there a generic way to search the nested-objects' structure for particular values?
I thought that was what $elemMatch was for.
Thank you.

I thought that was what $elemMatch was for...
From the docs: Using the $elemMatch query operator, you can match an entire document within an array.
This does not sounds like what you're looking for.
Is there a generic way to search the nested-objects' structure for particular values?
It sounds like you want to search "everything in object 'c' for an instance of 'e1'".
MongoDB supports two related features, but the features not quite what you're looking for.
Reach into objects, dot notation: db.test.find({'a.b.c.d1' : 'e1'})
Read through arrays: `db.test.find({'a.b.c.d4' : 'e5'})
It sounds like you're looking for the ability to do both at the same time. You want to "reach into objects" and "read through arrays" in the same query.
Unfortunately, I do not know of such a feature. You may want to file a feature request for this.

I believe the query you're looking for is
db.test.find({ 'a.b.c': { '$exists': true } });
To your credit, you were very close!

Related

Using Mongo query to find an in array element

Have records in my db with such structure:
{
"_id" : "YA14163134",
"discount" : "",
"retail" : "115.0000",
"cost" : "",
"description" : "Caterpillar Mens Big Twist Analog Watch",
"stock_update" : "05",
"brand" : "Kronos",
"img_url" : "image2342000.jpg",
"UPC" : "4895053708012",
"stock" : [ [ "1611292138", "5" ], [ "1612032232", "4" ], [ "1612050918", "0" ] ]
}
and looking for query to get all records that have in "stock" "1612050918" value. That is update id.
Trying something like:
db.vlc.find({stock: {$elemMatch:{$all:["1612050918"]}}})
or
db.vlc.find({stock: { $in : ['1611292138']}})
or
db.vlc.find({stock: { $all : [[1611292138]]}})
with no result. It works only if I include in request second array element like here
db.vlc.find({stock: { $all : [['1611292138', '7']]}})
but that limit my request to all items from update with qnty 7 when I need with any qnty. Thank you in advance!
use this query:
{
"stock" : {
"$elemMatch" : {
"$elemMatch" : {
"$eq" : "1611292138"
}
}
}
}
Explanation:
The first $elemMatch allows you to scan all three arrays under stock
The nex $elemMatch allows you to scan the two elements in the sub-arrays
since $elemMatch requires a query object, the $eq notation is used for a literal match.
If you know that "1611292138" will always be the first element of the sub-array, your query becomes simpler:
{ "stock" : { "$elemMatch" : { "0" : "1611292138" } } }
Explanation:
Scan all arrays under stock
Look for "1611292138" in the first slot of each sub-array
Use nested $elemMatch as below :
db.vlc.find({stock: { "$elemMatch":{"$elemMatch":{"$all":["1612050918"]}}}})
Or
db.vlc.find({stock: {"$elemMatch":{ "$elemMatch":{"$in" : ["1612050918"]}}}})

How to count and paginate subdocument which is an object in mongodb

I have data saved in the following:
{
"_id" : ObjectId("57723b5e009793e8f3cfd1d7"),
"room" : "1003",
"inout" : {
"1" : [
"i1654",
"o1656",
"i1706",
"o1707",
],
"2" : [
"i1655",
"o1656",
"i1715",
"o1715"
],
"3" : [
"i1801"
]
}
}
how to count and paginate the subdocument "inout" which is an object?
thanks!!!
Actually, there is a small modification required in your JSON. The "inout" should be an array to use the below solution.
"$unwind" can be used here.
Modified JSON to define "inout" as array rather than Object:-
db.rooms_second.insertOne({
"_id" : ObjectId("57723b5e009793e8f3cfd1d7"),
"room" : "1003",
"inout" : [
{"1" : [
"i1654",
"o1656",
"i1706",
"o1707",
]},
{"2" : [
"i1655",
"o1656",
"i1715",
"o1715"
]},
{"3" : [
"i1801"
]}
]
});
Mongodb Query:-
In the resultset, the below query will give you one record for each element in the "inout" array.
db.rooms_second.aggregate([ { $unwind: "$inout" } ])
The pagination can be done based on the driver and API that you are using (i.e. MongoDB Java Driver etc.).

Removing a (sub) array in MongoDB using $pull

So..I'm evaluating Mongodb for managing a bit of my JSON back end. I'm totally new to it and I had one problem that was just messy to do in code, so I thought — heck — let me check out to see if it's time to finally start using Mongo
I have a data structure that is approximately like this:
[
{
"_id" : ObjectId("526f59ee82f2e293f9833c54"),
"humans" : [
{
"serviceUsers" : [
{
"foo1" : "bar2",
"foo2" : "bar3"
},
{
"foo1" : "baz2",
"foo2" : "baz3"
}
]
}
]
}
]
And now I want to remove any serviceUsers array elements that have "foo1" equal to "baz2" so that ideally I would end up with this:
[
{
"_id" : ObjectId("526f59ee82f2e293f9833c54"),
"humans" : [
{
"serviceUsers" : [
{
"foo1" : "bar2",
"foo2" : "bar3"
},
]
}
]
}
]
I figured that $pull was the place to start. And I tried a bunch of contortions. If I'm in collection mytests, I tried
db.mytests.update({"humans.serviceUsers.foo1":"baz2"}, {$pull:{"humans.serviceUsers" : {"foo1":"baz2"}}}, {multi: true})
Which to my admittedly naive eye, seems like it should follow the $pull syntax:
db.collection.update( { field: <query> }, { $pull: { field: <query> } } );
Mongo doesn't complain. But it doesn't change the collection in any way, either.
I also tried
db.mytests.update({}, {$pull:{"humans.serviceUsers" : {"foo1":"baz2"}}}, {multi: true})
Which also failed.
Any suggestions are greatly appreciated.
Thus humans is also array, you should use positional $ operator to access serviceUsers array of matched humans element:
db.mytests.update({ "humans.serviceUsers.foo1" : "baz2" },
{ $pull: { "humans.$.serviceUsers" : { "foo1": "baz2" }}});

MongoDB: get documents by tags

I've got documents containing tags array. I want to provide tags based recommendations on site, so I need to get documents containing same tags + documents that don't match 1 tag + documents that don't match 2 tags and etc...
How do I do that?
example collection:
db.tags.insert({"tags":["red", "tall", "cheap"]});
db.tags.insert({"tags":["blue", "tall", "expensive"]});
db.tags.insert({"tags":["blue", "little", "cheap"]});
find all that include the tag "blue"
db.tags.find({tags: { $elemMatch: { $eq: "blue" } }})
find all tagged "blue" and only blue
db.tags.find({tags: "blue"})
find all tagged "blue" and "cheap"
db.tags.find({ tags: { $all: ["cheap", "blue"] } } )
find all not "blue"
db.tags.find({tags: { $ne: "blue" } })
find all "blue" and "cheap" but not "red" and not "tall"
not possible in my mongo db. From mongodb 1.9.1 on something like this should work, though (not tested):
db.tags.find({ $and: [ {tags: { $all: ["blue", "cheap"] } }, { tags: { $nin: ["red", "tall"] } } ] })
The rephrased question is:
Suppose if job postings have search tags attached like
Job Postings
[{_id : ObjectId(1249999493),tags : ['Location1', 'SkillSet1', 'SkillSet2', 'Someother1', 'Someother2']},
{_id : ObjectId(1249999494),tags : ['Location3', 'SkillSet1', 'SkillSet0', 'Someother4', 'Someother3']}]
Now, he wants the records having tags ['Location1','SkillSet1', 'SkillSet0']
And the selected docs having more keywords from the query should come first. Less keywords matching should come last. So, that one can get more suitable job posting for the search query.
Am I sensible or do I need to re-phrase ?
Steps:
Find matching products which contains any of the specified keys.
Unfold on keys
Do find again to filter unwanted after unfolding
Group them by adding key occurrence
Sort desc to get most relevant first
[{ "$match" : { "keys" : { "$in" : [ { "$regex" : "text" , "$options" : "i"}]}}}, { "$unwind" : "$keys"}, { "$match" : { "keys" : { "$in" : [ { "$regex" : "text" , "$options" : "i"}]}}}, { "$group" : { "_id" : { "productId" : "$productId"} , "relatedTags" : { "$sum" : 1} }}, { "$sort" : { "relatedTags" : -1}},{ "$limit" : 10}]

Mongodb array structure

Theres something here I can't quite figure out.
When I attempt to query an object with several fields I yield no results. The object structure looks like this:
{
"_id" : ObjectId("4d8b55f017a7303b0b000000"),
"title" : "Apollo",
"body" : "A spaceflight mission to the moon",
"tags" : [ [ "moon", "space", "nasa", "mission" ] ]
}
This is my query:
db.test.find({ tags: { $all: ['moon', 'mission'] } })
However I do get result by creating a new object with a single field:
{
"_id" : ObjectId("4d8b9e5935037b3c8228709c"),
"tags" : [ "apple", "banana", "pear" ]
}
... with the same query as the one above.
['tags'] isn't nested inside any other array, so why does it not return my search queries? Please enlighten me.
Sincerely,
Why
Why are you using a nested array
"tags" : [ [ "moon", "space", "nasa", "mission" ] ]
here?
This does not make any sense.
db.test.find({ tags: { $all: [ ['moon', 'mission'] ] } })