MongoDB nested array aggregation - mongodb

I want to aggregate data for the following sample array.
[
{
"_id": "5b7c0540342100091a375793",
"pages": [
{
"name": "ABCD",
"sections": [
{
"name": "sectionThird",
"id": 2,
"value": [
10,
50,
20
]
}
]
}
]
},
{
"_id": "5b3cd546342100514b4683a2",
"pages": [
{
"name": "ABCD",
"sections": [
{
"name": "sectionFourth",
"id": 2,
"value": [
19,
5,
8
]
},
{
"name": "sectionThird",
"id": 2,
"value": [
60
]
}
]
},
{
"name": "EFGH",
"sections": [
{
"name": "sectionFourth",
"id": 2,
"value": [
5
]
},
{
"name": "sectionThsads",
"id": 2,
"value": [
8
]
}
]
}
]
}
]
I want the following output:
[
{
"page": "ABCD",
"sections": [
{
"name": "sectionThird",
"totalValue": 140
},
{
"name": "sectionFourth",
"totalValue": 32
}
]
},
{
"page": "EFGH",
"sections": [
{
"name": "sectionFourth",
"totalValue": 5
},
{
"name": "sectionThsads",
"totalValue": 8
}
]
}
]
In the above sample array, you can see there are multiple documents with "page" as one of the keys which are also an array of objects. Each page object has a key "name" which is going to be unique for each object in "page" array. The "page" object has "sections" key and they also have "name" key in them which is going to be unique for each object.
So the output array is grouped by page.name then in that its grouped by sections.name from all the page objects with the sum of all the value array throughout sections inside a page object with the same section name.

You can use below aggregation.
$unwind each page and section followed by $group with $sum to sum the values for each section and $push to push the sections values back into page array.
db.col.aggregate([
{"$unwind":"$pages"},
{"$unwind":"$pages.sections"},
{"$group":{
"_id":{"pagename":"$pages.name","sectionname":"$pages.sections.name"},
"totalTime":{"$sum":{"$sum":"$pages.sections.value"}}
}},
{"$group":{
"_id":"$_id.pagename",
"sections":{"$push":{"name":"$_id.sectionname","totalTime":"$totalTime"}}
}}])

Related

How to do mongodb inner join and grouping

// orders
[
{
"id": 1,
"orderName": "a",
"seqId": 100,
"etc": [],
"desc": [],
},
{
"id": 2,
"orderName": "b",
"seqId": 200,
"etc": [],
"desc": []
},
{
"id": 3,
"orderName": "c",
"seqId": 100,
},
]
// goods collection
[
{
"id": 1,
"title": "example1",
"items": [
{
"id": 10,
"details": [
{
"id": 100
},
{
"id": 101,
}
]
},
{
"id": 20,
"details": [
{
"id": 102,
},
{
"id": 103,
}
]
},
]
},
[
{
"id": 2,
"title": "example2",
"items": [
{
"id": 30,
"details": [
{
"id": 200
},
{
"id": 201
}
]
},
{
"id": 40,
"details": [
{
"id": 202
},
{
"id": 203
}
]
},
]
},
]
When the etc field and desc field arrays of the orders collection are empty, or the non-empty document's seqId field value and the goods collection's "goods.details.id field value are the same.
I want to express the sum operation based on the title of the product collection and the sum if it is not empty.
{example1: 1, total: 2}
{example2: 1, total: 1}
For example, "example1" and "example2" represent the sum of the cases where the etc and desc field arrays are empty (the title of the goods collection), and the total represents the total regardless of whether the array is empty or not.
If so, it should be marked aboveas:
Following our discussion here, we can remove the early filtering for the 2 empty arrays and move it to a conditional sum at the $group stage.
db.orders.aggregate([
{
"$lookup": {
"from": "goods",
"localField": "seqId",
"foreignField": "items.details.id",
"as": "goodsLookup"
}
},
{
"$unwind": "$goodsLookup"
},
{
$group: {
_id: "$goodsLookup.title",
emptySum: {
$sum: {
"$cond": {
"if": {
$and: [
{
$eq: [
"$desc",
[]
]
},
{
$eq: [
"$etc",
[]
]
}
]
},
"then": 1,
"else": 0
}
}
},
total: {
$sum: 1
}
}
}
])
Mongo Playground

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

how to insert an object into the players array in mongoDB?

I have the document below and I need to insert an object into the players arrays how to do this with mongoDB
{
"data": {
"createTournament": {
"_id": "6130d9a565aa744f173a824a",
"title": "Jogo de truco",
"description": "",
"status": "PENDING",
"size": 8,
"prizePool": 20,
"currency": "USD",
"type": "Battle",
"entryFee": 1,
"startDate": "2021-09-01",
"endDate": "2021-09-01",
"rounds": [{
"round": 1,
"totalMatches": 4,
"matches": [{
"match": 1,
"players": []
}
]
}]
}
}
}
it will add 3 to array players that array matches has match of 1 and rounds array has round of 1
db.collection('exmaple').updateOne({},
{
$push:{"data.createTournament.rounds.$[outer].matches.$[inner].players":"3"}
},
{ "arrayFilters": [
{ "outer.round": 1 }, // you could change this to choose in which array must be pushed
{ "inner.match":1 } // // you could change this to choose in which array must be pushed
] }
)

MongoDB count values of multible nested documents

My data looks something like that:
[
{
"_id": 1,
"members": [
{
"id": 1,
"name": "name_1",
"assigned_tasks": [
1,
2,
3
]
},
{
"id": 1,
"name": "name_2",
"assigned_tasks": [
1
]
}
],
"tasks": [
{
"id": 1,
"name": "task_1",
},
{
"id": 2,
"name": "task_2",
},
{
"id": 3,
"name": "task_3",
}
]
}
]
I have a collection that represents a "class" which contains a list of members and a list of projects.
Each member can be assigned to multiple projects.
I wanna be able to count the number of members assigned to each of the tasks in the results and add it as a new field like:
[
{
"_id": 1,
"members": [
{
"id": 1,
"name": "name_1",
"assigned_tasks": [
1,
2,
3
]
},
{
"id": 1,
"name": "name_2",
"assigned_tasks": [
1
]
}
],
"tasks": [
{
"id": 1,
"name": "task_1",
"number_of_assigned_members":2
},
{
"id": 2,
"name": "task_2",
"number_of_assigned_members":1
},
{
"id": 3,
"name": "task_3",
"number_of_assigned_members":2
}
]
}
]
How can I create that query?
You can use $map and than $reduce,
$map tasks through object by object check in $reduce on members, if assigned_tasks is available or not, if available then add 1 otherwise 0,
db.collection.aggregate([
{
$addFields: {
tasks: {
$map: {
input: "$tasks",
as: "t",
in: {
$mergeObjects: [
"$$t",
{
number_of_assigned_members: {
$reduce: {
input: "$members",
initialValue: 0,
in: {
$cond: [
{ $in: ["$$t.id", "$$this.assigned_tasks"] },
{ $add: ["$$value", 1] },
"$$value"
]
}
}
}
}
]
}
}
}
}
}
])
Playground

MongoDB - Way to find closest results from arrays inside every document

I want to find closest result from array inside document for every doc, and project it new object using MongoDB. It will be easier to explain what I trying to do by example:
Doc schema:
{
"id": "string",
"name": "string",
"track" : [
{
"time": "number",
"distance": "number"
}
]
}
EXAMPLE:
I want to find closest results for every doc for time equals 4
Input data:
[
{
"id": "1",
"name": "test1",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 3,
"distance": 17
},
{
"time": 4,
"distance": 23
},
{
"time": 6,
"distance": 33
}
]
},
{
"id": "2",
"name": "test2",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 2,
"distance": 12
},
{
"time": 4,
"distance": 26
},
{
"time": 6,
"distance": 32
}
]
},
{
"id": "3",
"name": "test3",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 3,
"distance": 12
}
]
}
]
Output data:
[
{
"id": "1",
"result" : {
"time": 4,
"distance": 23
}
},
{
"id": "2",
"result" : {
"time": 4,
"distance": 26
}
},
{
"id": "3",
"result" : {
"time": 3,
"distance": 12
}
}
]
Is it possible to do this using MongoDB?
db.collection.aggregate([
{
"$addFields": {
"tracks": {
"$filter": {
"input": "$track",
"as": "track",
"cond": {
"$lte": [
"$$track.time",
4
]
}
}
}
}
},
{
"$addFields": {
"tracks": {
"$slice": [
"$tracks",
-1
]
}
}
},
{
"$unwind": "$tracks"
},
{
"$project": {
"tracks": 1,
"name": 1
}
}
])
Play
It does below things:
Finds whose track time is <=4 and adds it to an array called items
Then it gets the last element - i.e closer element
Take the element from array - unwind
Projects what is needed.