How to union/merge arrays of arrays in MongoDB using aggregations? - arrays

From this object:
{
"_id": null,
"reqs": [
["ab","ac","ab"],
["ac","cd"],
["ab","ae"]
]
}
How can I get this result using an aggregation:
{
"_id": null,
"reqs": ["ab","ac","cd","ae"]
}

Here it is:
mongos> db.a.find()
{ "_id" : ObjectId("5ff7a8c0bfa9f0b53f4b395d"), "reqs" : [ [ "ab", "ac", "ad" ], [ "ad", "dc", "ab" ], [ "ac", "ad", "dc" ] ] }
mongos> db.a.aggregate([{ $unwind:"$reqs"} , {$unwind:"$reqs" } , {$group:{_id:null , reqs:{$addToSet:"$reqs"}}} ])
{ "_id" : null, "reqs" : [ "ac", "ad", "dc", "ab" ] }
mongos>

Related

Return Documents with Same Subarray elements

I have the following collection:
{ "_id" : 1, "tags" : [ "school", "home" ] }
{ "_id" : 2, "tags" : [ "school", "storage", "home" ] }
{ "_id" : 3, "tags" : [ "school", "storage", "home", "bones" ] }
{ "_id" : 4, "tags" : [ "school", "storage", "home", "bones", "milk" ] }
{ "_id" : 5, "tags" : [ "homes", "maps", "bones" ] }
{ "_id" : 6, "tags" : [ "xxx", "yyy", "zzz" ] }
I would like to return all documents where "tags" matches documents with exactly the same array elements.
So thus, if I were to query for tags == ["school", "home"] or tags == ["home", "school"], document w/ _id=1 would be returned
I am doing the following:
db.test.find({tags: {$in: ['school', 'home']}}) or
db.test.find({tags: {$in: ['home', 'school']}})
and the following are returned:
{ "_id" : 1, "tags" : [ "school", "home" ] }
{ "_id" : 2, "tags" : [ "school", "storage", "home" ] }
{ "_id" : 3, "tags" : [ "school", "storage", "home", "bones" ] }
{ "_id" : 4, "tags" : [ "school", "storage", "home", "bones", "milk" ] }
How may I achieve only item w/ _id=1 be returned?
Maybe something like this:
Option 1:
db.collection.find({
$and: [
{
tags: "school"
},
{
tags: "home"
},
{
tags: {
$size: 2
}
}
]
})
Explained:
Match if school & home are in the tags array and if array size is 2.
Playground
Option 2:
db.collection.find({
$or: [
{
tags: [
"school",
"home"
]
},
{
tags: [
"home",
"school"
]
}
]
})
Explained:
Match the two possible array options
Playground2

$in Query on Array Field Mongo db

I have a doc like this
{
"_id" : "oidfi",
"users": [
{
"_id": "q",
"tags": ["a", "b", "c"],
"age": 20
},
{
"_id": "q",
"tags": ["x", "y", "z"],
"age": 30
}
],
"type": "repo"
}
I want to filter the users array with several fields ( I'm able to do that with the below query )
{
"$match": {
"$and": [
{
"_id": "a506f8af6f510f616bea14715276d474d2b363f0aef10443cc0f11559b139147"
}
]
}
},
{
"$project": {
"users": {
"$filter": {
"input": "$users",
"as": "users",
"cond": {
"$and": [
{
"$gte": [
"$$user.age",
15
]
}
]
}
}
}
}
}
]
is there a way for me to add condition where I give a list of tags items and get the users who are matching at least one item from their tags array
$$user.tags.containsAny(["a", "x"])
Thanks
You can do the followings in an aggregation pipeline:
$setIntersection to find out the intersection of the users.tags array and your input array i.e. ["a", "x"] in your example
$size to find the size of array in step 1
$match by the size of step 2 larger than 0
"anyTagsMatched": {
$gt: [
{
$size: {
"$setIntersection": [
"$users.tags",
[
"a",
"x"
]
]
}
},
0
]
}
Here is the Mongo playground for your reference.
You may have like following
db.collection.aggregate([
{
"$project": {
"users": {
"$filter": {
"input": "$users",
"cond": {
"$and": [
{ "$gte": [ "$$this.age", 15 ] },
{
$gt: [
{
$size: {
"$setIntersection": [
"$$this.tags",
[ "a", "x" ]
]
}
},
0
]
}
]
}
}
}
}
}
])
Working Mongo playground

Split arrays in set mongodb

I've been trying to make a set of strings < or arrays > but my main issue is that I can't use $unwind because of the other data.
To make it more clear I'll show an example:
This is how part of my documents look like:
{
"key": [
"a",
"b",
"c"
]
},
{
"key": [
"b",
"d"
]
},
{
"key": [
"e"
]
}
And I want to get an array like this:
{
"keys": [
"a",
"b",
"c",
"d",
"e"
]
}
or this:
{
"keys": [
["a"],
["b"],
["c"],
["d"],
["e"]
]
}
I just need unique values in there.
It would be so easy if I could use $unwind and then $addToSet. But as I said before I can't because of the other data that I need.
I was trying to use $cond inside the $addToSet but I don't know how to iterate through an array.
This pipeline doesn't work ->
db.collection.aggregate([
{
"$group": {
"_id": null,
"keys": {
"$addToSet": {
"$concatArrays": [
"$key",
"$this"
]
}
},
}
}
])
Maybe something like this:
{
"$group": {
"_id": null,
"keys": {
"$addToSet": {
"$cond": {
if: {
"$gt": [
{"$size": "$key"},
1
]
},
then: "<SPLIT THE ARRAY IN THE AMOUNT OF ELEMENTS>",
else: "$key"
}
}
}
}
}
I tried this but it doesn't work either.
db.collection.aggregate([
{
"$project": {
"keys": {
"$map": {
"input": {
"$range": [
0,
{
"$size": "$key"
},
1
]
},
as: "index",
in: {
$slice: [
"$key",
"$$index",
1
]
}
}
}
}
},
{
"$group": {
"_id": null,
"keys": {
"$addToSet": {
"$concatArrays": [
"$keys"
]
}
},
}
}
])
Here is my code snippet: https://mongoplayground.net/p/sMENXyrbQgI
Could someone please guide me! I'll appreciate it so much.
So the idea is to use $setUnion along with $reduce to pick unique values from the array:
Solution in MongoPlayground
Try this query:
db.collection.aggregate([
{
$group: {
_id: null,
"keys": { $push: "$key" }
}
},
{
$addFields: {
"keys": {
$reduce: {
input: "$keys",
initialValue: [],
in: {
$setUnion: ["$$value", "$$this"]
}
}
}
}
}
])
Output:
{
"_id" : null,
"keys" : [
"a",
"b",
"c",
"d",
"e"
]
}
Test data in collection:
[
{
"key": [
"a",
"b",
"c"
]
},
{
"key": [
"b",
"d",
"a",
]
},
{
"key": [
"e",
"b"
]
}
]

Jolt transform array value to object

I am trying to transform array value as string to my object using jolt. When I convert array value to String, I am not able to get the proper value in my object.
Input Json :
"id": [
"123",
"245"
],
"lastName": [
"john",
"Mary"
],
"firstName": [
"doe",
"Ann"
],
"subjects": [
[
"['Maths']",
"['Science']",
"['English']"
],
[
"['English']",
"['Accounts']",
"['Art']"
]
]
}
Jolt Spec:
[{
"operation": "shift",
"spec": {
"*": {
"*": {
"*": {
"$": "[&2].&3"
}
}
}
}
}]
Expected output :
[ {
"id" : "123",
"lastName" : "john",
"firstName" : "doe",
"subjects" : [ ["['Maths']","['Science']","['English']"] ]
}, {
"id" : "245",
"lastName" : "Mary",
"firstName" : "Ann",
"subjects" : [ ["['English']","['Accounts']","['Art']"] ]
} ]
Actual Output:
[ {
"id" : "123",
"lastName" : "john",
"firstName" : "doe",
"subjects" : [ "0", "1", "2" ]
}, {
"id" : "245",
"lastName" : "Mary",
"firstName" : "Ann",
"subjects" : [ "0", "1", "2" ]
} ]
Please help. Thanks in advance.
Check if this solves it. Think you were missing a level at the subjects array:
[{
"operation": "shift",
"spec": {
"*": {
"*": {
"*": {
"$": "[&2].&3"
}
}
},
"subjects": {
"*": {
"*": {
"*": {
"$": "[&3].&4"
}
}
}
}
}
}]
cheers

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" ] }

Resources