MongoDB - Aggregate deep tree structures - mongodb

I would like to extract tree graph from my database
This is my structure (which always is always a tree graph)
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b2"), "title" : "a", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b3") } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b3"), "title" : "b", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b4") } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b4"), "title" : "c", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b5") }, { "_id" : ObjectId("59490a250f86a4b4e0cb75b6") } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b5"), "title" : "d" }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b6"), "title" : "e", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b7") } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b7"), "title" : "f" }
I was trying to do something like this
db.test3.aggregate([{
$lookup: {
from: "test3",
localField: "_id",
foreignField: "_id",
as: "array"
}
}])
But then I just receive
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b2"), "title" : "a", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b2"), "title" : "a", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b3") } ] } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b3"), "title" : "b", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b3"), "title" : "b", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b4") } ] } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b4"), "title" : "c", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b4"), "title" : "c", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b5") }, { "_id" : ObjectId("59490a250f86a4b4e0cb75b6") } ] } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b5"), "title" : "d", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b5"), "title" : "d" } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b6"), "title" : "e", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b6"), "title" : "e", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b7") } ] } ] }
{ "_id" : ObjectId("59490a250f86a4b4e0cb75b7"), "title" : "f", "array" : [ { "_id" : ObjectId("59490a250f86a4b4e0cb75b7"), "title" : "f" } ] }
but this doesnt seems to work as expected

According to description as mentioned in above question please try executing following aggregate query in MongoDB shell
db.test3.aggregate(
// Pipeline
[
// Stage 1
{
$unwind: {
path : "$array"
}
},
// Stage 2
{
$lookup: {
"from" : "mycoll",
"localField" : "array._id",
"foreignField" : "_id",
"as" : "arr"
}
}
]
);

Related

MongoDB Cross-Collection Query

Assuming the following structure:
Assets
{
"_id" : LUUID("d34a3fed"),
"name" : "A",
"records" : [
LUUID("3627f3ac"),
LUUID("80e9d125"),
LUUID("4d5e8af5"),
LUUID("17593a39"),
}
Records
{
"_id" : LUUID("3627f3ac"),
"Fields" : [
{
"Name" : "foo",
"Value" : "bar",
}
],
}
My goal is to use a find() or aggregate() to cross-reference the two collections above. The two collections share the LUUID values.
{"records": "LUUID("3627f3ac")"}
{"_id": "LUUID("3627f3ac")"}
Ultimately retrieving the:
{"Fields.Name": "foo"}
name of the Records collection
Maybe something like this:
mongos> db.records.find()
{ "_id" : ObjectId("5ff8ccf9e0f1b975b90d7a86"), "fields" : [ { "name" : "foo", "value" : "bar" } ] }
{ "_id" : ObjectId("5ff8ccf9e0f1b975b90d7a87"), "fields" : [ { "name" : "foo2", "value" : "bar2" } ] }
{ "_id" : ObjectId("5ff8ccf9e0f1b975b90d7a88"), "fields" : [ { "name" : "foo3", "value" : "bar3" } ] }
mongos> db.assest.find()
{ "_id" : ObjectId("5ff8cd72e0f1b975b90d7a87"), "name" : "A", "records" : [ ObjectId("5ff8ccf9e0f1b975b90d7a86"), ObjectId("5ff8ccf9e0f1b975b90d7a87") ] }
mongos> db.assest.aggregate([ { $lookup:{ from:"records" , localField:"records" , foreignField:"_id" , as:"match" } } , {$unwind:"$match"} , {$unwind:"$match.fields"} ,{$project:{ "Fields_name":"$match.fields.name" ,_id:0}} ])
{ "Fields_name" : "foo" }
{ "Fields_name" : "foo2" }
mongos>
Playground

MongoDB - Find duplicated elements in record property

I'm struggling to identified duplicated elements in my MongoDB records, here is my problem :
I have a Mongo collection named "elements".
Example of a record in this collection :
{
"_id" : ObjectId("5d1b2204e851271e80c824b6"),
"name" : "A",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826a5")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826ad")
}
]
}
I would like to identify records where the array "items" contains objects with the same "ref_id".
In my example we can see that the last two objects of the "items" array have the same "ref_id" : ObjectId("5d1b2204e851271e80c823d5").
I tried a bunch of aggregate function but unfortunately couldn't came out with a solution.
The following query can get us the expected output:
db.elements.aggregate([
{
$unwind:"$items"
},
{
$group:{
"_id":"$_id",
"root":{
$first:"$$ROOT"
},
"items":{
$push:"$items"
},
"distinctItems":{
$addToSet: "$items.ref_id"
}
}
},
{
$match:{
$expr:{
$ne:[
{
$size:"$items"
},
{
$size:"$distinctItems"
}
]
}
}
},
{
$addFields:{
"root.items":"$items"
}
},
{
$replaceRoot:{
"newRoot":"$root"
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d1b2204e851271e80c824b6"),
"name" : "A",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826a5")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826ad")
}
]
}
{
"_id" : ObjectId("5d654b9d7d0ab652c42315f2"),
"name" : "B",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
}
]
}
Output:
{
"_id" : ObjectId("5d1b2204e851271e80c824b6"),
"name" : "A",
"items" : [
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d7"),
"_id" : ObjectId("5d1b2205e851271e80c82534")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d6"),
"_id" : ObjectId("5d1b2205e851271e80c82533")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d8"),
"_id" : ObjectId("5d1b2205e851271e80c82532")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826a5")
},
{
"ref_id" : ObjectId("5d1b2204e851271e80c823d5"),
"_id" : ObjectId("5d1b3048e851271e80c826ad")
}
]
}
Explanation: We are populating an array of distinct ref_id from each document and matching if the size of the populated array is equal to the size of actual items array.

MongoDB aggregation $elemMatch inside $lookup stage

I have a MongoDB collection that is looking like this:
{
players: [
{uuid: "A"},
{uuid: "B"}
]
},
{
players: [
{uuid: "A"},
{uuid: "C"}
]
},
{
players: [
{uuid: "D"},
{uuid: "E"}
]
}
I want to use results of a previous aggregation stage and now find all documents where a player shows up, using a $lookup stage:
from: "collection",
pipeline: [
{
$match: {
players: {
$elemMatch: {
uuid: "$playerId"
}
}
//using "players.uuid": "$playerId" doesn't work either
}
}
],
as: "field"
The input to my $lookup stage looks like this:
{
"playerId" : "A"
}
{
"playerId" : "B"
}
{
"playerId" : "C"
}
This query returns an empty array in field. It seems like $uuid is not getting evaluated correctly, because if I exchange $uuid with a hardcoded value (e.g. A), this query returns results.
I have also tried using the let property, this gave me the same result.
What am I doing wrong?
Using the documents you've provided. I believe this might work for you:
I've used $lookup to do a join onto the collection which holds the playerId, which creates an array called field. I then use $unwind to extract all the array elements from both field and player. Finally I use $cond to crosscheck if both values match.
db.getCollection('foo').aggregate([
{ $lookup : {
from: "bar",
localField: "players.uuid",
foreignField: "playerId",
as: "field"
} },
{ $unwind : "$players" },
{ $unwind : "$field" },
{ $project : {
"players": 1,
"field" : 1,
"isMatch": {
"$cond": [ { "$eq": ["$players.uuid", "$field.playerId"] }, 1, 0 ]
} } }
])
I've purposely left the output verbose..
/* 1 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 1.0
}
/* 2 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f539b337e8d2b97ff2fff"),
"playerId" : "B"
},
"isMatch" : 0.0
}
/* 3 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "B"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 0.0
}
/* 4 */
{
"_id" : ObjectId("5a7f534b337e8d2b97ff2ffb"),
"players" : {
"uuid" : "B"
},
"field" : {
"_id" : ObjectId("5a7f539b337e8d2b97ff2fff"),
"playerId" : "B"
},
"isMatch" : 1.0
}
/* 5 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 1.0
}
/* 6 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "A"
},
"field" : {
"_id" : ObjectId("5a7f53a8337e8d2b97ff3000"),
"playerId" : "C"
},
"isMatch" : 0.0
}
/* 7 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "C"
},
"field" : {
"_id" : ObjectId("5a7f5374337e8d2b97ff2ffe"),
"playerId" : "A"
},
"isMatch" : 0.0
}
/* 8 */
{
"_id" : ObjectId("5a7f5356337e8d2b97ff2ffc"),
"players" : {
"uuid" : "C"
},
"field" : {
"_id" : ObjectId("5a7f53a8337e8d2b97ff3000"),
"playerId" : "C"
},
"isMatch" : 1.0
}

How to join deeply nested array?

Here is my actual database schema.
company_id is reference object of companies collection and booking_days.consultants.consultant_id is reference object of users collection.
I want to join embedded document with company_id and booking_days.consultants.consultant_id.
{
"_id" : ObjectId("5a7040d664544e1bb877deae"),
"company_id" : ObjectId("5a6eb43f437e6a0d9e00c92f"),
"booking_days" : [
{
"booking_date" : ISODate("2018-01-31T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877deca"),
"consultants" : [
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"_id" : ObjectId("5a7040d664544e1bb877decc")
},
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52f"),
"_id" : ObjectId("5a7040d664544e1bb877decb")
}
]
},
{
"booking_date" : ISODate("2018-02-01T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877dec6"),
"consultants" : [
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52f"),
"_id" : ObjectId("5a7040d664544e1bb877dec9")
},
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"_id" : ObjectId("5a7040d664544e1bb877dec8")
},
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"_id" : ObjectId("5a7040d664544e1bb877dec7")
}
]
},
{
"booking_date" : ISODate("2018-02-02T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877dec4"),
"consultants" : [
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"_id" : ObjectId("5a7040d664544e1bb877dec5")
}
]
},
],
"__v" : 0
}
I am using below query.
db.getCollection('booking_days').aggregate(
[
{ $match: { company_id:ObjectId("5a6eb43f437e6a0d9e00c92f") } },
{
$lookup: {
localField: "company_id",
from: "companies",
foreignField: "_id",
as: "companies"
},
},
{
$lookup: {
localField: "booking_days.consultants.consultant_id",
from: "users",
foreignField: "_id",
as: "userssss"
},
},
{
$unwind:"$companies"
},
]
)
Actual Output
{
"_id" : ObjectId("5a7040d664544e1bb877deae"),
"company_id" : ObjectId("5a6eb43f437e6a0d9e00c92f"),
"booking_days" : [
{
"booking_date" : ISODate("2018-01-31T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877deca"),
"consultants" : [
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"_id" : ObjectId("5a7040d664544e1bb877decc")
},
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52f"),
"_id" : ObjectId("5a7040d664544e1bb877decb")
}
]
},
{
"booking_date" : ISODate("2018-02-01T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877dec6"),
"consultants" : [
{
"consultant_id" : ObjectId("5a6f2854ce7d6938de1dd52f"),
"_id" : ObjectId("5a7040d664544e1bb877dec9")
},
]
},
],
"__v" : 0,
"companies" : {
"_id" : ObjectId("5a6eb43f437e6a0d9e00c92f"),
"first_name" : "Adrienne Runolfsson",
},
"users" : [
{
"_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"first_name" : "Christ Hamill",
},
{
"_id" : ObjectId("5a6f2854ce7d6938de1dd52e"),
"first_name" : "Miss Dina Kovacek",
},
]
}
Excepted output. consultant data will come in booking_days.consultants array.
{
"_id" : ObjectId("5a7040d664544e1bb877deae"),
"company_id" : ObjectId("5a6eb43f437e6a0d9e00c92f"),
"booking_days" : [
{
"booking_date" : ISODate("2018-01-31T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877deca"),
"consultants" : [
{
"consultant_id" : {
"_id" : ObjectId("5a6f2854ce7d6938de1dd52c"),
"first_name" : "Christ Hamill",
},
"_id" : ObjectId("5a7040d664544e1bb877decc")
},
{
"consultant_id" : {
"_id" : ObjectId("5a6f2854ce7d6938de1dd52e"),
"first_name" : "Miss Dina Kovacek",
},
"_id" : ObjectId("5a7040d664544e1bb877decb")
}
]
},
{
"booking_date" : ISODate("2018-02-01T00:00:00.000Z"),
"_id" : ObjectId("5a7040d664544e1bb877dec6"),
"consultants" : [
{
"consultant_id" : {
"_id" : ObjectId("5a6f2854ce7d6938de1dd52e"),
"first_name" : "Miss Dina Kovacek",
},
"_id" : ObjectId("5a7040d664544e1bb877dec9")
},
]
},
],
"__v" : 0,
"companies" : {
"_id" : ObjectId("5a6eb43f437e6a0d9e00c92f"),
"first_name" : "Adrienne Runolfsson",
},
}
As such you have to $unwind the localField when it is an embedded document array expect in some cases where localField is an array of scalar ids.
$unwind twice as consultant array is two levels deep followed by $lookup to get the name and $group to get back the expected output.
db.getCollection('booking_days').aggregate([
{"$match":{"company_id":ObjectId("5a6eb43f437e6a0d9e00c92f")}},
{"$lookup":{"localField":"company_id","from":"companies","foreignField":"_id","as":"companies"}},
{"$unwind":"$companies"},
{"$unwind":"$booking_days"},
{"$unwind":"$consultants"},
{"$lookup":{
"localField":"booking_days.consultants.consultant_id",
"from":"users",
"foreignField":"_id",
"as":"booking_days.consultants.consultant_id"
}},
{"$group":{
"_id":{"_id":"$_id","booking_days_id":"$booking_days._id"},
"company_id":{"$first":"$company_id"},
"booking_date":{"$first":"$booking_days.booking_date"},
"companies":{"$first":"$companies"},
"consultants":{"$push":"$booking_days.consultants"}
}},
{"$group":{
"_id":"$_id._id",
"company_id":{"$first":"$company_id"},
"companies":{"$first":"$companies"},
"booking_days":{
"$push":{
"_id":"$_id.booking_days_id",
"booking_date":"$booking_date",
"consultants":"$consultants"
}
}
}}
])
{"Id": "5b87a4c79a9c3feac943fc6c",
"comments" : [
{
"likes" : [],
"_id" : ObjectId("5b87a4c79a9c3feac943fc6c"),
"comment" : "string",
"accountId" : "a426d0da-ac72-4932-828e-3af99a998bc7",
"commentId" : "7d2a05d1-2026-4a13-a5c1-318ed80d1b38",
"reply" : [
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string",
"accountId" : "a426d0da-ac72-4932-828e-3af99a998bc7",
"replyId" : "ec220fd7-3440-44dc-9178-7a1183879463"
},
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string klllll",
"accountId" : "a426d0da-ac72-4932-828e-3af99a998bc7",
"replyId" : "ec220fd7-3440-44dc-9178-7a1183879463"
}
]
},
{
"likes" : [],
"_id" : ObjectId("5b87c301c8a07efa2599c29e"),
"comment" : "testing",
"accountId" : "cfd29f53-d73e-480c-9cfa-ea42b4119266",
"commentId" : "0676047b-1712-4f70-89d5-29c1abe03eaf",
"reply" : [
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string",
"accountId" : "a426d0da-ac72-4932-828e-3af99a998bc7",
"replyId" : "ec220fd7-3440-44dc-9178-7a1183879463"
},
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string klllll",
"accountId" : "a426d0da-ac72-4932-828e-3af99a998bc7",
"replyId" : "ec220fd7-3440-44dc-9178-7a1183879463"
}
]
}
]
}
accountId is in differnt connection
// Expected Out Put
{"Id": "5b87a4c79a9c3feac943fc6c",
"comments" : [
{
"likes" : [],
"_id" : ObjectId("5b87a4c79a9c3feac943fc6c"),
"comment" : "string",
"name" : "apple",
"reply" : [
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string",
"name" : "apple",
},
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string klllll",
"name" : "apple",
}
]
},
{
"likes" : [],
"_id" : ObjectId("5b87c301c8a07efa2599c29e"),
"comment" : "testing",
"name" : "ball",
"reply" : [
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string",
"name" : "apple",
},
{
"_id" : ObjectId("5b87b61e97585ef1d0d22108"),
"comment" : "string klllll",
"name" : "apple", }
]
}
]
}

how to get this query in mongoDB

I have this collection...
> db.banks.find().pretty()
{
"_id" : ObjectId("54f37cbb44aec3b01b7db8f4"),
"name" : "A",
"branches" : [
{
"branch_id" : 8561,
"name" : "X",
},
{
"branch_id" : 8576,
"name" : "Y",
}
]
}
{
"_id" : ObjectId("54f37cbb44aec3b01b7db8f5"),
"name" : "B",
"branches" : [
{
"branch_id" : 3238,
"name" : "Z",
}
]
}
with this command :
db.banks.aggregate({$project{"branches.name":1,"_id":0}});
get this result :
{ "branches" : { { "name" : "X" }, { "name" : "Y" } } }
{ "branches" : { { "name" : "Z" } } }
but; how I get this result?
(In fact, one object and without "branches".)
{{"name" : "X"}, {"name" : "Y"}, {"name" : "Z"}}
very thanks...
One way you could go about this is to do an $unwind first in the aggregation pipeline to get a deconstructed array with a document for each element and then group by the array element $branches.name:
db.banks.aggregate([
{ $unwind: '$branches'},
{
$group: {
_id: {
name: '$branches.name'
}
}
},
{
$project: {
_id: 0,
name: '$_id.name'
}
},
{ $sort : { "name" : 1 } }
])
Outputs:
{
"result" : [
{
"name" : "X"
},
{
"name" : "Y"
},
{
"name" : "Z"
}
],
"ok" : 1
}