How do I do a '$all $in' on mongodb? - arrays

I have the following collection
>db.prueba.find({})
{ "_id" : "A", "requi" : null }
{ "_id" : "B", "requi" : null }
{ "_id" : "C", "requi" : [ "A" ] }
{ "_id" : "D", "requi" : [ "A", "B" ] }
{ "_id" : "E", "requi" : [ "C" ] }
{ "_id" : "F", "requi" : [ "B", "D"] }
{ "_id" : "G", "requi" : [ "F" ] }
I need each element of the requi field to be in the following array. in this case, the array has only one element
["A", "D"]
When I use the operator $all $in returns the following
>db.prueba.find({requi:{$elemMatch:{$in:['A','D']}}})
{ "_id" : "C", "requi" : [ "A" ] }
{ "_id" : "D", "requi" : [ "A", "B" ] }
{ "_id" : "F", "requi" : [ "B", "D" ] }
the query must returns only document, because 'B' not exists in the array ["A" , "D"]
{ "_id" : "C", "requi" : [ "A" ] }
please, help me

You can use $setIsSubset to check whether the given array is set of the requi array and then $redact to eliminate the non-matched ones.
db.collection.aggregate([
{ "$match": { "requi": { "$ne": null } } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$setIsSubset": ["$requi", ["A", "D"]] }, true] },
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])

Related

How do I merge arrays from multiple documents without duplicates in MongoDB aggregation?

I have 3 documents:
{
"id": 1,
"user": "Brian1",
"configs": [
"a",
"b",
"c",
"d"
]
}
----
{
"id": 2,
"user": "max_en",
"configs": [
"a",
"h",
"i",
"j"
]
}
----
----
{
"id": 3,
"user": "userX",
"configs": [
"t",
"u",
"s",
"b"
]
}
I want to merge all the "configs" arrays into one array without dublicates,like this:
{
"configs": [
"a",
"b",
"c",
"d",
"h",
"i",
"j",
"t",
"u",
"s",
]
}
I've tried the following:
Aggregation.group("").addToSet("configs").as("configs") and { _id: "", 'configs': { $addToSet: '$configs' } }
The first one gives an error because I've left the fieldname empty (I don't know what to put there).
The second one returns a merged array but with duplicates.
When you want to group all the documents, you need to add {_id: null}
It means group all documents.
Probably you need this
db.collection.aggregate([
{
"$unwind": "$configs"
},
{
$group: {
_id: null,
configs: {
"$addToSet": "$configs"
}
}
}
])
But be cautious when you need to use on larger collection without a match.

Strange behaviour with MongoDB sort operation

Here is the information collection and sample data:
Query to get all docs with eid:abc and sorted by role.
db.information.find({eid:"abc"}).sort({role:1}) giving expected
result, but when changing eid:aaa, result is not coming in sorting
order, order is random.
On contradictory when changing sort object to role:-1, its sorting
output in ascending order but then for eid:abc output comes in
descending order. it's just behaving strangely.
Using MongoDB shell version v4.0.6 :
information =[
{_id:'110',role:'dev',eid:'aaa',info:["a","b"]},
{_id:'111',role:'tester',eid:'abc',info:["a","b","c"]},
{_id:'112',role:'admin',eid:'abc',info:["a","c"]}
{_id:'113',role:'admin',eid:'abc',info:["a","b","c"]},
{_id:'114',role:'dev',eid:'abc',info:["a","b","c"]},
{_id:'115',role:'admin',eid:'aaa',info:["a","b","c"]}
];
Output:
1.when .find({eid:"aaa"}).sort:{role:1}
=>
[
{_id:'115',role:'admin',eid:'aaa',info:["a","b","c"]}
{_id:'110',role:'dev',eid:'aaa',info:["a","b"]},
];
2.when .find({eid:"abc"}).sort:{role:1}
=> [
{_id:'111',role:'tester',eid:'abc',info:["a","b","c"]},
{_id:'114',role:'dev',eid:'abc',info:["a","b","c"]}
{_id:'112',role:'admin',eid:'abc',info:["a","c"]}
{_id:'113',role:'admin',eid:'abc',info:["a","b","c"]}];
3.when .find({eid:"aaa"}).sort:{role:-1}
=>
[{_id:'110',role:'dev',eid:'aaa',info:["a","b"]}
{_id:'115',role:'admin',eid:'aaa',info:["a","b","c"]}]
4.when .find({eid:"abc"}).sort:{role:-1}
=>
[{_id:'113',role:'admin',eid:'abc',info:["a","b","c"]},
{_id:'112',role:'admin',eid:'abc',info:["a","c"]},
{_id:'111',role:'tester',eid:'abc',info:["a","b","c"]},
{_id:'114',role:'dev',eid:'abc',info:["a","b","c"]}]
This is what I got with a similar environment using Mongo Shell. The sort works fine for all four cases.
Note that the find query filter is on the field eid and the sort is applied on the field role.
> db.sorts.find()
{ "_id" : "110", "role" : "dev", "eid" : "aaa", "info" : [ "a", "b" ] }
{ "_id" : "111", "role" : "tester", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "112", "role" : "admin", "eid" : "abc", "info" : [ "a", "c" ] }
{ "_id" : "113", "role" : "admin", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "114", "role" : "dev", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "115", "role" : "admin", "eid" : "aaa", "info" : [ "a", "b", "c" ] }
> db.sorts.find({ eid: "aaa" }).sort({ role: 1 })
{ "_id" : "115", "role" : "admin", "eid" : "aaa", "info" : [ "a", "b", "c" ] }
{ "_id" : "110", "role" : "dev", "eid" : "aaa", "info" : [ "a", "b" ] }
> db.sorts.find({ eid: "abc" }).sort({ role: 1 })
{ "_id" : "112", "role" : "admin", "eid" : "abc", "info" : [ "a", "c" ] }
{ "_id" : "113", "role" : "admin", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "114", "role" : "dev", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "111", "role" : "tester", "eid" : "abc", "info" : [ "a", "b", "c" ] }
> db.sorts.find({ eid: "aaa" }).sort({ role: -1 })
{ "_id" : "110", "role" : "dev", "eid" : "aaa", "info" : [ "a", "b" ] }
{ "_id" : "115", "role" : "admin", "eid" : "aaa", "info" : [ "a", "b", "c" ] }
> db.sorts.find({ eid:"abc" }).sort({ role: -1 })
{ "_id" : "111", "role" : "tester", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "114", "role" : "dev", "eid" : "abc", "info" : [ "a", "b", "c" ] }
{ "_id" : "112", "role" : "admin", "eid" : "abc", "info" : [ "a", "c" ] }
{ "_id" : "113", "role" : "admin", "eid" : "abc", "info" : [ "a", "b", "c" ] }

MongoDB - find any document with array combinations

mongo documents are like:
{
_id: '',
names: ['ab', 'bc']
}
{
_id: '',
names: ['ab', 'de', 'fg']
}
{
_id: '',
names: ['bc']
}
{
_id: '',
names: ['ab', 'bc', 'cd']
}
I have an input array:
['ab', 'bc', 'cd']
Question : How to get all the documents, where 'names' is equal to any combination of the input array ?
Result : all documents where 'names' is any of below should return
['ab']
['bc']
['cd']
['ab', 'bc']
['bc', 'ab']
['bc', 'cd']
['cd', 'bc']
... and so on..
['ab', 'bc', 'cd']
You can use $expr in find to get the $size of $setIntersection with names array
db.tt.find({$expr : {$gt : [{$size : {$setIntersection : ["$names", ["ab","bc","cd"]]}}, 0]}})
sample collection
> db.tt.find()
{ "_id" : "1", "names" : [ "ab", "bc" ] }
{ "_id" : "2", "names" : [ "ab", "de", "fg" ] }
{ "_id" : "3", "names" : [ "bc" ] }
{ "_id" : "4", "names" : [ "ab", "bc", "cd" ] }
with $expr and $setIntersection
> db.tt.find({$expr : {$gt : [{$size : {$setIntersection : ["$names", ["ab","bc","cd"]]}}, 0]}})
{ "_id" : "1", "names" : [ "ab", "bc" ] }
{ "_id" : "2", "names" : [ "ab", "de", "fg" ] }
{ "_id" : "3", "names" : [ "bc" ] }
{ "_id" : "4", "names" : [ "ab", "bc", "cd" ] }
with $in (as given in comments by Anthony)
> db.tt.find({names : {$in : ["ab","bc","cd"]}})
{ "_id" : "1", "names" : [ "ab", "bc" ] }
{ "_id" : "2", "names" : [ "ab", "de", "fg" ] }
{ "_id" : "3", "names" : [ "bc" ] }
{ "_id" : "4", "names" : [ "ab", "bc", "cd" ] }

jolt array transform using wildcard

I'm using JOLT to transform data from:
[{"a" : "a",
"b" : "b",
"c" : "c",
...},
{"a" : "a",
"b" : "b",
"c" : "c",
...}]
To:
[{"a1" : "a",
"b1" : "b",
"c1" : "c",
...},
{"a1" : "a",
"b1" : "b",
"c1" : "c",
...}]
I'm trying to figure out a wild card that would map all the attributes I don't need to change. Something like:
[{
"operation": "shift",
"spec": {
"*": {
"a": "[&1].a1",
"b": "[&1].b1",
"c": "[&1].c1",
"*": {
"#": "&"
}
}
}
}]
Where:
"*": {
"#": "&"
}
Would work as a wildcard for all the fields I don't need to update.
Spec
[{
"operation": "shift",
"spec": {
"*": {
"a": "[&1].a1",
"b": "[&1].b1",
"c": "[&1].c1",
"*": "[&1].&"
}
}
}]

the $elemMatch operator does not work correctly in mongodb

I have the following collection
>db.prueba.find({})
{ "_id" : "A", "requi" : null }
{ "_id" : "D", "requi" : [ "A", "B" ] }
{ "_id" : "E", "requi" : [ "B" ] }
{ "_id" : "B", "requi" : null }
{ "_id" : "C", "requi" : [ "A" ] }
I need each element of the requi field to be in the following array. in this case, the array has only one element
['A']
When I use the operator $elemMatch returns the following
db.prueba.find({requi:{$elemMatch:{$in:['A']}}})
{ "_id" : "D", "requi" : [ "A", "B" ] }
{ "_id" : "C", "requi" : [ "A" ] }
the query must returns only document
{ "_id" : "C", "requi" : [ "A" ] }
please, help me
Use $eq operator to find the exact match in the array
db.collection.find({ "requi": { "$eq": [ "A" ] } })
Output
[
{
"_id": "C",
"requi": [
"A"
]
}
]
Check it here

Resources