Triple Nested Array MongoDB Query - mysql

I'd like to find the correct query to return all Boards within the Boards collection where the member id matches 1. Any takers?
My schema as follows:
Within the 'Boards' collection,
{ name: 'Board One',
teams: [
{ name: 'Team One',
members: [
{ id: '1', name: 'Garrett' },
{ id: '2', name: 'Sarah' }
]
},
{ name: 'Team Two',
members: [
{ id: '1', name: 'Garrett' },
{ id: '2', name: 'Jeff' }
]
}
]
},`{ name: 'Board Two',
teams: [
{ name: 'Team One',
members: [
{ id: '1', name: 'Garrett' },
{ id: '2', name: 'Sarah' }
]
},
{ name: 'Team Three',
members: [
{ id: '1', name: 'Jim' },
{ id: '2', name: 'Samson' }
]
}
]
I'm trying to query a object within an array, within array of objects, within a collection. I've tried many variations on the following query..
Boards.find({
'teams': {
$elemMatch: {
'members' : {
$elemMatch :
{
'id' : Meteor.userId()
}
}
}
}
})
I'd like to find the correct query to return all Boards within the Boards collection where the member id matches 1.

Could this be because you are storing id as string in the collection? As you will see below I tried your query replacing Meteor.userId() with a hardcoded string value (with single or double quotes) like '1' or '3' and I believe the query output is what you are looking for.
> db.boards.find().pretty()
{
"_id" : ObjectId("567443e7fba7a186bcd48bfd"),
"name" : "Board One",
"teams" : [
{
"name" : "Team One",
"members" : [
{
"id" : "1",
"name" : "Garrett"
},
{
"id" : "2",
"name" : "Sarah"
}
]
},
{
"name" : "Team Two",
"members" : [
{
"id" : "1",
"name" : "Garrett"
},
{
"id" : "2",
"name" : "Jeff"
}
]
}
]
}
{
"_id" : ObjectId("5674441ffba7a186bcd48bfe"),
"name" : "Board Two",
"teams" : [
{
"name" : "Team One",
"members" : [
{
"id" : "1",
"name" : "Garrett"
},
{
"id" : "2",
"name" : "Sarah"
}
]
},
{
"name" : "Team Three",
"members" : [
{
"id" : "1",
"name" : "Jim"
},
{
"id" : "2",
"name" : "Samson"
}
]
}
]
}
>
> db.boards.find({
... 'teams': {
... $elemMatch: {
... 'members' : {
... $elemMatch :
... {
... 'id' : '1'
... }
... }
... }
... }
... })
{ "_id" : ObjectId("567443e7fba7a186bcd48bfd"), "name" : "Board One", "teams" : [ { "name" : "Team One", "members" : [ { "id" : "1", "name" : "Garrett" }, { "id" : "2", "name" : "Sarah" } ] }, { "name" : "Team Two", "members" : [ { "id" : "1", "name" : "Garrett" }, { "id" : "2", "name" : "Jeff" } ] } ] }
{ "_id" : ObjectId("5674441ffba7a186bcd48bfe"), "name" : "Board Two", "teams" : [ { "name" : "Team One", "members" : [ { "id" : "1", "name" : "Garrett" }, { "id" : "2", "name" : "Sarah" } ] }, { "name" : "Team Three", "members" : [ { "id" : "1", "name" : "Jim" }, { "id" : "2", "name" : "Samson" } ] } ] }
>
>
> db.boards.find({
... 'teams': {
... $elemMatch: {
... 'members' : {
... $elemMatch :
... {
... 'id' : '3'
... }
... }
... }
... }
... })
>
>

Related

Query with aggregate, lookup and pipeline in Mongodb

I have to manage a wall with comments, each wall have many parent comments and each parent comment have child comments.
my collection walls is like this
groupId : {type: Schema.Types.ObjectId, ref: 'groups', unique: true},
comments : [{
commentId : {type: Schema.Types.ObjectId, ref: 'comments'},
user : {type: Schema.Types.ObjectId, ref: 'users'},
}],
and the collection comments is like this
text : String,
parentCommentId : {type: Schema.Types.ObjectId, ref: 'comments', default : null},
I want to display my wall by parent comments, each child comment under its parent comment.
i tried this query but it didn't return any results
db.getCollection('walls').aggregate([
{$match: {groupId: ObjectId("5e8c5caa75b1cd342a1175eb")}},
{
"$lookup": {
from: "comments",
let: { item: "$comments.commentId" },
pipeline: [
{ $match:
{ $expr: { $eq: [ "$parentCommentId", "$$item" ] }
}
},
{ $project: {
"_id": 1,
"parentCommentId": 1,
"text": 1
} }
],
as: "comments"
}
},
{
$project: {
groupId: 1,
"comments":1,
date: 1
}
}
])
data in walls
{
"_id" : ObjectId("5e95b4b49d3e303d667a8b71"),
"groupId" : ObjectId("5e8c5caa75b1cd342a1175eb"),
"comments" : [
{
"_id" : ObjectId("5e95b4b49d3e303d667a8b72"),
"commentId" : ObjectId("5e95b4b49d3e303d667a8b70")
},
{
"_id" : ObjectId("5e95b4ef80ae1244693aa857"),
"commentId" : ObjectId("5e95b4ef80ae1244693aa856")
},
{
"_id" : ObjectId("5e95b51080ae1244693aa859"),
"commentId" : ObjectId("5e95b51080ae1244693aa858")
},
{
"_id" : ObjectId("5e95b51d80ae1244693aa85b"),
"commentId" : ObjectId("5e95b51d80ae1244693aa85a")
},
{
"_id" : ObjectId("5e95b53580ae1244693aa85e"),
"commentId" : ObjectId("5e95b53580ae1244693aa85c")
}
],
}
data in comments
{
"_id" : ObjectId("5e95b4b49d3e303d667a8b70"),
"parentCommentId" : null,
"text" : "Hello parent 1"
}
{
"_id" : ObjectId("5e95b4ef80ae1244693aa856"),
"parentCommentId" : null,
"text" : "Hello parent 2",
"date" : ISODate("2020-04-14T13:04:47.860Z")
}
{
"_id" : ObjectId("5e95b51080ae1244693aa858"),
"parentCommentId" : ObjectId("5e95b4b49d3e303d667a8b70"),
"text" : "Hello child 1 parent 1"
}
{
"_id" : ObjectId("5e95b51d80ae1244693aa85a"),
"parentCommentId" : ObjectId("5e95b4b49d3e303d667a8b70"),
"text" : "Hello child 2 parent 1"
}
{
"_id": "5e95b53580ae1244693aa85c",
"parentCommentId": "5e95b4ef80ae1244693aa856",
"text": "Hello child 1 parent 2",
}
desired result
{
"success": true,
"data": [
{
"_id": "5e95b4b49d3e303d667a8b71",
"groupId": "5e8c5caa75b1cd342a1175eb",
"comments": [
{
"_id": "5e95b4b49d3e303d667a8b70",
"parentCommentId": null,
"text": "Hello parent 1",
"childs": {
{
"_id": "5e95b51080ae1244693aa858",
"parentCommentId": "5e95b4b49d3e303d667a8b70",
"text": "Hello child 1 parent 1",
},
{
"_id": "5e95b51d80ae1244693aa85a",
"parentCommentId": "5e95b4b49d3e303d667a8b70",
"text": "Hello child 2 parent 1",
},
}
},
{
"_id": "5e95b4ef80ae1244693aa856",
"parentCommentId": null,
"text": "Hello parent 2",
"childs": {
{
"_id": "5e95b53580ae1244693aa85c",
"parentCommentId": "5e95b4ef80ae1244693aa856",
"text": "Hello child 1 parent 2",
}
}
},
],
}
]
}
How can i modify my query ? thank you.
You can use below aggregation
db.walls.aggregate([
{ "$lookup": {
"from": "comments",
"let": { "commentIds": "$comments.commentId" },
"pipeline": [
{ "$match": {
"$expr": { "$in": ["$_id", "$$commentIds"] },
"parentCommentId": null
}},
{ "$sort": { "text": -1 }},
{ "$graphLookup": {
"from": "comments",
"startWith": "$_id",
"connectFromField": "parentCommentId",
"connectToField": "parentCommentId",
"as": "childs"
}}
],
"as": "comments"
}}
])
MongoPlayground

MongoDB query filter array of objects and format return object

I have a MongoDB collection like this:
{
"_id" : "course1",
"teams" : [
{
"key" : "1548600639880X5269760768997986",
"title": "Team One",
"members" : {
"user1" : true
}
},
{
"key" : "1548601941683X14679065888073906",
"title": "Team Two",
"members" : {
"user2" : true,
"user3" : true
}
},
{
"key" : "1548602385020X41594057288000386",
"title": "Team Three",
"members" : {
"user4" : true
}
}
],
"updated_at" : "2019-01-27T15:31:43+00:00"
}
I'am trying to get the "team" of user2 with all user with value true. So the return object schould be something like this:
{
"key" : "1548601941683X14679065888073906",
"title": "Team Two",
"members" : {
"user2" : true,
"user3" : true
}
}
I tried a lot with db.getCollection('').find({}) but did not get the needed result.
You need to use aggregation. And below aggregation help you.
db.getCollection('').find({}) can't be convert output into desire result.
db.getCollection('collection').aggregate([
{ $unwind: "$teams" },
{ $match: {"teams.members.user2": true } },
{ $replaceRoot: { newRoot: "$teams" } }
])
db.getCollection('teams').find({
"_id": "course1",
"teams.members": { "user1": true }
})
gets me
{
"_id" : "course1",
"teams" : [
{
"key" : "1548600639880X5269760768997986",
"title" : "Team One",
"members" : {
"user1" : true
}
},
{
"key" : "1548601941683X14679065888073906",
"title" : "Team Two",
"members" : {
"user2" : true,
"user3" : true
}
},
{
"key" : "1548602385020X41594057288000386",
"title" : "Team Three",
"members" : {
"user4" : true
}
}
],
"updated_at" : "2019-01-27T15:31:43+00:00"
}

Mongodb Aggregate JSON array field for the matching field of other collection

I am new to mongodb , I have two collections like this :
1st collection name is A
{
"_id": "1234",
"versions": [{
"owner_id": ObjectId("100000"),
"versions": 1,
"type" : "info",
"items" : ["item1","item3","item7"]
},
{
"owner_id": ObjectId("100001"),
"versions": 2,
"type" : "bug",
"OS": "Ubuntu",
"Dependencies" : "Trim",
"items" : ["item1","item7"]
}
]}
2nd Collection name is B
{ "_id": ObjectId("100000"), "email": "abc#xyz.com" } { "_id": ObjectId("100001"), "email": "bbc#xyz.com"}
Expected output is :
{
"_id": "1234",
"versions":[{
"owner_id": "abc#xyz.com",
"versions": 1,
"type" : "info",
"items" : ["item1","item3","item7"]
},
{
"owner_id": "bbc#xyz.com",
"versions": 2,
"type" : "bug",
"OS": "Ubuntu",
"Dependencies" : "Trim",
"items" : ["item1","item7"]
}
] }
I used mongo $lookup but I am not getting required output
Please help.
Thank You!!!
You need to $unwind versions, $lookup with another collection on foreignField, $project to take the first element from the match array, $group to get back in original document format
collection a
> db.a.find()
{ "_id" : "1234", "versions" : [ { "owner_id" : "100000" }, { "owner_id" : "100001" }, { "owner_id" : "100001" } ] }
collection b
> db.b.find()
{ "_id" : "100000", "email" : "abc#xyz.com" }
{ "_id" : "100001", "email" : "bbc#xyz.com" }
aggregate pipeline
> db.a.aggregate(
[
{$unwind:"$versions"},
{$lookup : {from : "b", "localField":"versions.owner_id", "foreignField":"_id", as :"out"}},
{$project : {"_id":1, "versions.owner_id":{$arrayElemAt:["$out.email",0]}}},
{$group:{_id:"$_id", versions : {$push : "$versions"}}}
]
).pretty()
output
{
"_id" : "1234",
"versions" : [
{
"owner_id" : "abc#xyz.com"
},
{
"owner_id" : "bbc#xyz.com"
},
{
"owner_id" : "bbc#xyz.com"
}
]
}

Get Array element from JSON array from mongodb document

{
"employees" : [
{
"name" : "XXX",
"id" : "1",
"Salary" : [
{
"Month" : "XXXX",
"Amount" : "XXXX",
},
{
"Month" : "XXXX",
"Amount" : "XXXX",
},
{
"Month" : "XXXX",
"Amount" : "XXXX",
}
]
},
{
"name" : "YYY",
"id" : "2",
"Salary" : [
{
"Month" : "YYYY",
"Amount" : "YYYY",
},
{
"Month" : "YYYY",
"Amount" : "YYYY",
},
{
"Month" : "YYYY",
"Amount" : "YYYY",
}
]
}
],
}
This is sample of json format in mongodb document.
I want to get the result as a one particular element from employees Array that search by name
I tried these methods
db.abc.find({"employees.name": "XXX"},{employees: {$elemMatch: {name: "XXX"}}});
and
db.abc.find({ employees: { $elemMatch: { name: "XXX"} } })
none of those won't work. those methods give whole document as a result. can anyone give me a solution on that.
Try this
db.abc.find({"employees.name": "XXX"},{"employees.$":1})

How to unwind single document and then process into single result in an array

I have had some great help from #Joao and #Blakes Seven in order to get me as far as I've got. Awesome, thanks guys very much.
What I have a problem with is going from my original simple example and applying it to my real life scenario.
Where I've got to is two separate scripts which work perfectly by themselves but when I try to being the two together, it then only does the first part without applying the second part; it's my lack of experience in Mongo letting me down here.
So, I am able to get a name value pair from the first array set within a document using the following code:
db.raw_originBusinessData.aggregate([
{ "$match": {objectOriginAPI : "Profit & Loss"}}
,{ "$unwind": "$objectRawOriginData.Reports" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows.Rows" }
,{ "$group": {"_id": "$_id","first": { "$first": "$objectRawOriginData.Reports.Rows.Rows.Cells.Value" }
, "temp": { "$push": "$objectRawOriginData.Reports.Rows.Rows.Cells.Value" }
}},
{ "$unwind": "$temp" }
,{"$skip":1}
,{ "$group": {"_id": "$_id", "AccountBalance":{ "$first": "$first" }
}}
])
This gives me the result below, which I'm happy with except for the fact I am not able to name the two values in the Account Balances array.
Mission 1: I want AccountBalance to be an array and the first position has two values: "AccountName" : "Sales", "AccountValue" : 5428.04.
{
"result" : [
{
"_id" : ObjectId("564d12da1506995581569428"),
"AccountBalance" : [
"Sales",
"5428.64"
]
}
],
"ok" : 1.0000000000000000
}
The second part of the problem is that it is only processing one set of values whereas, the document I am processing on has 9 sets to do. I have run the following $unwind on the document and it has perfectly split them into 9 results:
db.raw_originBusinessData.aggregate([
// find document
{ "$match": {objectOriginAPI : "Profit & Loss"}}
// unwind into multiple documents
,{ "$unwind": "$objectRawOriginData.Reports" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows.Rows" }
])
So I get 9 results perfect. Mission 2: What I want to do is to combine this with the script I showed above. I tried the following but it does absolutely no more than the script just above.
db.raw_originBusinessData.aggregate([
// find document
{ "$match": {objectOriginAPI : "Profit & Loss"}}
// unwind into multiple documents
,{ "$unwind": "$objectRawOriginData.Reports" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows.Rows" }
]
// process each document
,{ "$unwind": "$objectRawOriginData.Reports" }
, {"$unwind": "$objectRawOriginData.Reports.Rows" }
, {"$unwind": "$objectRawOriginData.Reports.Rows.Rows" }
, {"$group": {"_id": "$_id","first": { "$first": "$objectRawOriginData.Reports.Rows.Rows.Cells.Value" }
, "a": { "$push": "$objectRawOriginData.Reports.Rows.Rows.Cells.Value" }
}},
{ "$unwind": "$a" }
,{"$skip":1}
,{ "$group": {"_id": "$_id", "AccountBalance":{ "$first": "$first" }
}}
)
Desired Outcome
What I want to get is the following. This is combination of mission 1 and 2.
{
"result" : [
{
"_id" : ObjectId("564d12da1506995581569428"),
"AccountBalance" : [
{"AccountName" : "Sales",
"AccountValue" : "5428.64"},
{"AccountName" : "Total Income",
"AccountValue" : "5428.64"},
{"AccountName" : "Cost of Sales",
"AccountValue" : "100.00"},
{"AccountName" : "Total Cost of Sales",
"AccountValue" : "100.00"},
{"AccountName" : "Gross Profit",
"AccountValue" : "5328.64"},
{"AccountName" : "Advertising",
"AccountValue" : "100.00"},
{"AccountName" : "General Expenses",
"AccountValue" : "100.00"},
{"AccountName" : "Total Operating Expenses",
"AccountValue" : "200.00"},
{"AccountName" : "Net Profit",
"AccountValue" : "5128.64"}
]
}
],
"ok" : 1.0000000000000000
}
The document that I am using as a source is from Xero API - it's one of their reports. It has the same pattern as most reports exported in JSON like Oracle. Below is the actual report so that you have it for reference.
Thanks a million guys, very much appreciated!
{
"_id" : ObjectId("564d12da1506995581569428"),
"objectClass" : "Origin Data",
"objectCategory" : "Application",
"objectType" : "Customer",
"connection_id" : "562033dfca91840cd0c7c54f",
"connectionName" : "Building Accounts",
"entity_id" : "564149bcca9183a8d0c7c83c",
"objectCreationDate" : "2015-11-19 14:43:40",
"objectCycleID" : "12345678",
"objectStatus" : "PROCESSED",
"objectOrigin" : "Xero",
"objectOriginAPI" : "Profit & Loss",
"objectOriginService" : "Xero API - Profit & Loss v 1.0.0.8",
"objectRawOriginData" : {
"Id" : "d6e7fb37-9f2e-45ae-b0a4-de62aa95a783",
"Status" : "OK",
"ProviderName" : "Xero API Previewer",
"DateTimeUTC" : "/Date(1443405874333)/",
"Reports" : [
{
"ReportID" : "ProfitAndLoss",
"ReportName" : "Profit and Loss",
"ReportType" : "ProfitAndLoss",
"ReportTitles" : [
"Profit & Loss",
"Paddy's markets",
"28 September 2014 to 28 September 2015"
],
"ReportDate" : "28 September 2015",
"UpdatedDateUTC" : "/Date(1443405874333)/",
"Fields" : [],
"Rows" : [
{
"RowType" : "Header",
"Cells" : [
{
"Value" : ""
},
{
"Value" : "28 Sep 15"
}
]
},
{
"RowType" : "Section",
"Title" : "Income",
"Rows" : [
{
"RowType" : "Row",
"Cells" : [
{
"Value" : "Sales",
"Attributes" : [
{
"Value" : "a7e3f9e4-6f63-4b25-ae36-107131e8b9be",
"Id" : "account"
}
]
},
{
"Value" : "5428.64",
"Attributes" : [
{
"Value" : "a7e3f9e4-6f63-4b25-ae36-107131e8b9be",
"Id" : "account"
}
]
}
]
},
{
"RowType" : "SummaryRow",
"Cells" : [
{
"Value" : "Total Income"
},
{
"Value" : "5428.64"
}
]
}
]
},
{
"RowType" : "Section",
"Title" : "Less Cost of Sales",
"Rows" : [
{
"RowType" : "Row",
"Cells" : [
{
"Value" : "Cost of Sales",
"Attributes" : [
{
"Value" : "f78f7118-ad98-4862-a63c-39dd3c5ace8a",
"Id" : "account"
}
]
},
{
"Value" : "100.00",
"Attributes" : [
{
"Value" : "f78f7118-ad98-4862-a63c-39dd3c5ace8a",
"Id" : "account"
}
]
}
]
},
{
"RowType" : "SummaryRow",
"Cells" : [
{
"Value" : "Total Cost of Sales"
},
{
"Value" : "100.00"
}
]
}
]
},
{
"RowType" : "Section",
"Title" : "",
"Rows" : [
{
"RowType" : "Row",
"Cells" : [
{
"Value" : "Gross Profit"
},
{
"Value" : "5328.64"
}
]
}
]
},
{
"RowType" : "Section",
"Title" : "Less Operating Expenses",
"Rows" : [
{
"RowType" : "Row",
"Cells" : [
{
"Value" : "Advertising",
"Attributes" : [
{
"Value" : "67466588-132b-48ce-b897-0ceabffd7a9d",
"Id" : "account"
}
]
},
{
"Value" : "100.00",
"Attributes" : [
{
"Value" : "67466588-132b-48ce-b897-0ceabffd7a9d",
"Id" : "account"
}
]
}
]
},
{
"RowType" : "Row",
"Cells" : [
{
"Value" : "General Expenses",
"Attributes" : [
{
"Value" : "fdb25d7a-2fc8-406a-bf4b-6b4e8014b8cb",
"Id" : "account"
}
]
},
{
"Value" : "100.00",
"Attributes" : [
{
"Value" : "fdb25d7a-2fc8-406a-bf4b-6b4e8014b8cb",
"Id" : "account"
}
]
}
]
},
{
"RowType" : "SummaryRow",
"Cells" : [
{
"Value" : "Total Operating Expenses"
},
{
"Value" : "200.00"
}
]
}
]
},
{
"RowType" : "Section",
"Title" : "",
"Rows" : [
{
"RowType" : "Row",
"Cells" : [
{
"Value" : "Net Profit"
},
{
"Value" : "5128.64"
}
]
}
]
}
]
}
]
}
}
done it, see below, thanks:
db.raw_originBusinessData.aggregate([
{ "$match": {objectOriginAPI : "Profit & Loss"}}
,{ "$unwind": "$objectRawOriginData.Reports" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows" }
,{ "$unwind": "$objectRawOriginData.Reports.Rows.Rows" }
,{ "$group": {"_id": "$_id","accountBalances": { "$push": "$objectRawOriginData.Reports.Rows.Rows.Cells.Value" }
}},
])