Extracting unique elements from array within different arrays - mongodb

I have a collection with this structure:
{
"name": "1",
"array1": [
{
"arrayname1A" : "A",
"array2": [
{ "value": "1" },
{ "value": "3" }
]
},
{
"arrayname1B": "B",
"array2": [
{ "value": "5" },
]
}
]
},
{
"name": "2",
"array1": [
{
"arrayname1A": "A",
"array2": [
{ "value": "1" },
{ "value": "7" }
]
}
]
}
How can I extract the unique "value" from every different array2? The end result I am looking for would be something like "1","3","5","7" with no repeated values.

Simply use the distinct() method and the dot notation to access the "value" field.
db.collection.distinct('array1.array2.value')
which yields:
[ "1", "3", "5", "7" ]

Related

PyMongo - Update the field for the object in nested array

Trying to update the nested object for the document in MongoDB.
{
"items" : [
{
"id": 1,
"name": "a",
"child": [
{ "id": 11, "name": "aa" },
{ "id": 12, "name": "bb" },
]
},
]
}
Need to update the child id to 13 whose name is "aa".
O/P, which I am trying to get
{
"items" : [
{
"id": 1,
"name": "a",
"child": [
{ "id": 13, "name": "aa" },
{ "id": 12, "name": "bb" },
]
},
]
}
Work with $[<identifier>] filtered positional operator and arrayFilters.
db.collection.update({
"items.child.name": "aa"
},
{
$set: {
"items.$[].child.$[c].id": 13
}
},
{
arrayFilters: [
{
"c.name": "aa"
}
]
})
Sample Mongo Playground

powershell - filter nested object which contains data from list

I am looking for a way to filter nested objects with PowerShell. Let's say I have a list that contains UPN addresses.
$UPN = "user1#xyz.com", "user5#xyz.com"
In the below object converted to JSON, I want to get only those objects where "Attr1" within whole object contains any address from the above list.
[
{
"Id": "1",
"Name": "XYZ",
"Attr1": [
{
"Id": "1",
"UPN": "user1#xyz.com"
},
{
"Id": "2",
"UPN": "user2#xyz.com"
},
{
"Id": "3",
"UPN": "user3#xyz.com"
}
],
"Attr2": [
{
"Id": "1",
[...]
}
],
"Attr3": [
{
"Id": "1",
[...]
},
{
"Id": "2",
[...]
}
]
},
{
"Id": "2",
"Name": "XYZ",
"Attr1": [
{
"Id": "1",
"UPN": "user2#xyz.com"
}
],
"Attr2": [
],
"Attr3": [
{
"Id": "1",
[...]
}
]
}
]
How to filter such an object? The standard method to not work for me (I am not getting the desired result, losing data):
$CollectionOfObjects | Where-Object {$_.Attr1.UPN -in $UPN}
How to handle this?
Regards!
You need to nest Where-Object calls to get the desired result, or, for better performance with in-memory collections, .Where() method calls:
$CollectionOfObjects.Where({ $_.Attr1.Where({ $_.UPN -in $UPN }, 'First') })
Tip of the hat to Manuel Batsching for his help.
Note: The 'First' argument isn't strictly necessary, but can improve performance, as it stops enumerating the elements of the array in .Attr1 as soon as a match is found.
As an aside: Where-Object has no equivalent feature - enumeration invariably continues.
GitHub issue #13834 suggests bringing all the extra features .Where() supports to Where-Object too.
A self-contained example with simplified data:
$UPN = 'user1#xyz.com', 'user6#xyz.com'
$CollectionOfObjects = ConvertFrom-Json #'
[
{
"Id": "1",
"Name": "XYZ1",
"Attr1": [
{
"Id": "1",
"UPN": "user1#xyz.com"
},
{
"Id": "2",
"UPN": "user2#xyz.com"
},
{
"Id": "3",
"UPN": "user3#xyz.com"
}
],
"Attr2": [ ],
"Attr3": [ ]
},
{
"Id": "2",
"Name": "XYZ2",
"Attr1": [
{
"Id": "1",
"UPN": "user4#xyz.com"
},
{
"Id": "2",
"UPN": "user5#xyz.com"
}
],
"Attr2": [ ],
"Attr3": [ ]
},
{
"Id": "3",
"Name": "XYZ3",
"Attr1": [
{
"Id": "1",
"UPN": "user6#xyz.com"
}
],
"Attr2": [ ],
"Attr3": [ ]
}
]
'#
$CollectionOfObjects.Where({ $_.Attr1.Where({ $_.UPN -in $UPN }, 'First') })
Output, showing that the two objects of interest were successfully identified:
Id : 1
Name : XYZ1
Attr1 : {#{Id=1; UPN=user1#xyz.com}, #{Id=2; UPN=user2#xyz.com}, #{Id=3; UPN=user3#xyz.com}}
Attr2 : {}
Attr3 : {}
Id : 3
Name : XYZ3
Attr1 : {#{Id=1; UPN=user6#xyz.com}}
Attr2 : {}
Attr3 : {}

Mongodb: How to merge $facet output 2 by 2?

Playground:https://mongoplayground.net/p/YUV_fReyGsr
I have following query. I need to combine the result 2 by 2. Meaning I need to combine facet "1","2" as a result and facet "3","4" as another result. It's guaranteed that the number of facet will be even. Also, each pair of facet should get at most one record(it might not matter)
db.collection.aggregate([
{
"$facet": {
"1": [
{
$match: {
"ID": "2"
}
}
],
"2": [
{
$match: {
"array.ID": "2"
}
}
],
"3": [
{
$match: {
"array.ID": "4"
}
}
],
"4": [
{
$match: {
"ID": "4"
}
}
]
}
}
])
The expected result will be
[
{
"1": [
{
"ID": "1",
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
],
"attr1": "123"
}
],
"2": [
{
"ID": "4",
"array": [
{
"ID": "5",
"attr1": "456"
}
],
"attr1": "123"
}
]
}
]
I was able to figure this out using $concatArrays operator, along with $project.
Live demo here
Database
[
{
"ID": "1",
"attr1": "123",
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
]
},
{
"ID": "4",
"attr1": "123",
"array": [
{
"ID": "5",
"attr1": "456"
}
]
}
]
Query
db.collection.aggregate([
{
"$facet": {
"1": [
{
$match: {
"ID": "2"
}
}
],
"2": [
{
$match: {
"array.ID": "2"
}
}
],
"3": [
{
$match: {
"array.ID": "4"
}
}
],
"4": [
{
$match: {
"ID": "4"
}
}
]
}
},
{
"$project": {
_id: 0,
"1": {
"$concatArrays": [
"$1",
"$2"
]
},
"2": {
"$concatArrays": [
"$3",
"$4"
]
}
}
}
])
Result
[
{
"1": [
{
"ID": "1",
"_id": ObjectId("5a934e000102030405000000"),
"array": [
{
"ID": "2",
"attribute1": "456"
},
{
"ID": "3",
"attribute1": "567"
}
],
"attr1": "123"
}
],
"2": [
{
"ID": "4",
"_id": ObjectId("5a934e000102030405000001"),
"array": [
{
"ID": "5",
"attr1": "456"
}
],
"attr1": "123"
}
]
}
]

Filter by nested arrays/objects values (on different levels) and $project by matching groups (on a specific level) - MongoDB Aggregate

Considering I have the following collection (ignoring documents _id):
Collection
[
{
"Id": "1",
"Level2": [
{
"Id": "1.1",
"Level3": [
{
"Id": "1.1.1",
"Level4": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
]
},
{
"Id": "1.1.2",
"Level4": [
{
"Id": "1.1.2.1",
"Status": "a"
},
{
"Id": "1.1.2.2",
"Status": "c"
}
]
},
{
"Id": "1.1.3",
"Level4": [
{
"Id": "1.1.3.1",
"Status": "c"
}
]
}
]
}
]
},
{
"Id": "2",
"Level2": [
{
"Id": "2.1",
"Level3": [
{
"Id": "2.1.1",
"Level4": [
{
"Id": "2.1.1.1",
"Status": "a"
}
]
}
]
}
]
}
]
Conditions
I want to query it such as:
Level2.Id: "1.1"
Level2.Level3.Level4.Status $in ["a", "b"]
The $project should:
Group Level2.Level3.Level4 matches by Level2.Level3
Should not include Level2.Level3 if it is an empty array
The expected result should be:
Result 1
[
{
"Id": "1.1.1",
"Level4": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
]
},
{
"Id": "1.1.2",
"Level4": [
{
"Id": "1.1.2.1",
"Status": "a"
}
]
}
]
Please notice that if current Level2.Id: "2.1" has the value "1.1" instead, the result should be (matches on different documents):
Result 2
[
{
"Id": "1.1.1",
"Level4": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
]
},
{
"Id": "1.1.2",
"Level4": [
{
"Id": "1.1.2.1",
"Status": "a"
}
]
},
{
"Id": "2.1.1",
"Level4": [
{
"Id": "2.1.1.1",
"Status": "a"
}
]
}
]
How can I accomplish this with an aggregate query?
( filtering different levels and grouping by some level )
Here it is the answer (thank you to #Vijay Rajpurohit for his help on this):
db.collection.aggregate([
{
$unwind: "$Level2"
},
{
$unwind: "$Level2.Level3"
},
{
$unwind: "$Level2.Level3.Level4"
},
{
$match: {
"Level2.Id": "1.1",
"Level2.Level3.Level4.Status": {
$in: [
"a",
"b"
]
}
}
},
{
$group: {
"_id": "$Level2.Level3.Id",
"Messages": {
$push: "$Level2.Level3.Level4"
}
}
}
])
The result of this query is:
[
{
"Messages": [
{
"Id": "1.1.2.1",
"Status": "a"
}
],
"_id": "1.1.2"
},
{
"Messages": [
{
"Id": "1.1.1.1",
"Status": "a"
},
{
"Id": "1.1.1.2",
"Status": "b"
}
],
"_id": "1.1.1"
}
]
Mongo Playground

Update many nested array in mongodb

In below document i have to update the "value": "7" object.How can i do that.if one array means we can use $.if we know index of the array also we can do that but in my case i cant apply more than one $ and also i don't have index info.
{
"data": [
{
"value": "1",
"children": [
{
"value": "2",
"children": [
{
"value": "3",
"children": [
{
"value": "4",
"children": [
{
"value": "aaa"
}
]
}
]
}
]
},
{
"value": "5",
"children": [
{
"value": "6",
"children": [
{
"value": "7",
"children": [ // i want to update this value
{
"value": "bbb"
}
]
}
]
}
]
}
]
}
]
}