merge multiple documents into one document with both document fields in MongoDB - arrays

I have multiple documents In MobgoDB How to do to the group on "abc" and "xyz" and get one document. Please see the "Output Document".
need to do the union with ( Document 1 U Document 2 ) and (Document 1 U Document 3) .
U= Union
Document 1
{
"data": {
"Inside_data": {
"project": {
"abc": {
"alpha": 4,
"beta" : 45
},
"xyz": {
"alpha": 214,
"beta" : 431
}
}
}
}
}
Document 2
"Deal": {
"name": "abc",
"url" : "www.abc.com,
"email": [ "abc#gmail.com"],
"total": 2
}
Document 3
"Deal": {
"name": "xyz",
"url" : "www.googl.com,
"email": [ "xyz#gmail.com"],
"total": 25
}
Expected Output.
{
{
"name": "abc",
"url" : "www.abc.com,
"email": "abc#gmail.com",
"total": 2,
"alpha": 4,
"beta" : 45
},
{
"name": "xyz",
"url" : "www.googl.com,
"email": "xyz#gmail.com",
"total": 25,
"alpha": 214,
"beta" : 431
}
}

db.collection.aggregate([
{
$match: {
Deal: {
$exists: true
}
}
},
{
$lookup: {
from: "collection",
let: {
name: "$Deal.name"
},
pipeline: [
{
$match: {
data: {
$exists: true
}
}
},
{
$project: {
data: {
$reduce: {
input: {
$objectToArray: "$data.Inside_data.project"
},
initialValue: {},
in: {
$cond: [
{
$eq: [
"$$this.k",
"$$name"
]
},
"$$this.v",
"$$value"
]
}
}
}
}
},
{
$project: {
_id: 0,
alpha: "$data.alpha",
beta: "$data.beta"
}
}
],
as: "Deal.data"
}
},
{
$unwind: "$Deal.data"
}
])
Answer by #turivishal

Related

Issue with MongoDB array aggregation and grouping by key in array of objects

Considering an array like the one below which i'm trying to group by date and sum the durations:
[
{
"allDates": [
{
"duration": 153,
"date": "2021-10"
},
{
"duration": 20,
"date": "2021-11"
},
{
"duration": 181,
"date": "2021-11"
},
{
"duration": 180,
"date": "2021-11"
}
]
}
]
I'm trying to achieve a sum of the duration but grouped by the dates.
This is what i've tried so far:
db.collection.aggregate([
{
$addFields: {
durations: {
$arrayToObject: {
$map: {
input: "$allDates",
as: "allDate",
in: {
k: {
$toString: "$$allDate.date"
},
v: {
$sum: {
$map: {
input: "$allDates",
as: "kv",
in: {
$cond: {
if: {
$eq: [
{
$toString: "$allDate.date"
},
{
$toString: "$$kv.k"
}
]
},
then: "$$kv.duration",
else: 0
}
}
}
}
}
}
}
}
},
}
}
])
Unfortunately the result i get is:
[
{
"allDates": [
{
"date": "2021-10",
"duration": 153
},
{
"date": "2021-11",
"duration": 20
},
{
"date": "2021-11",
"duration": 181
},
{
"date": "2021-11",
"duration": 180
}
],
"durations": {
"2021-10": 534,
"2021-11": 534
}
}
]
So it's adding them all up for every key instead of for each one separately, what am i missing here?
Basically I'm expecting to get:
...
"durations": {
"2021-10": 153,
"2021-11": 381
}
Try this one:
db.collection.aggregate([
{
$unwind: "$allDates"
},
{
$group: {
_id: "$allDates.date",
duration: {
$sum: "$allDates.duration"
}
}
},
{
$group: {
_id: null,
durations: {
$push: {
k: "$_id",
v: "$duration"
}
}
}
},
{
$project: {
_id: 0,
durations: {
$arrayToObject: "$durations"
}
}
}
])
Mongo Playground

How to add the index number from the array in MongoDB

Explanation: How I can add the index of the array. please check the expected output, I have that array 10000+ elemets
[
{
"data": [
[
1000
],
[
20
],
[
300
],
[
40
]
]
}
]
The expected output will be with the index number.
{
"data": [{
"value": 1000,
"Index": 1
},
{
"value": 20,
"Index": 2
},
{
"value": 300,
"Index": 3
},
{
"value": 40,
"Index": 4
}
]
}
Would be this one:
db.collection.aggregate([
{
$set: {
data: {
$map: {
input: { $range: [0, { $size: "$data" }] },
as: "idx",
in: {
index: { $add: ["$$idx", 1] },
value: { $first: { $arrayElemAt: ["$data", "$$idx"] } }
}
}
}
}
}
])
Mongo Playground

get the relevant information against the object value in MongoDB

Explanation :
A , B , C object have values. I have to match only those values with dic.data objects name. if its not match the then get the exception "No error found". see the Expected_output.
A B C get the relvant information.
I am using lookup to get dic data.
Note this should be handle dynamically. A B C values may differ, that impact on Expected_output
{
"_id": {
"A": "31",
"B": "40",
"C": "7"
},
"dic": [
{
"_id": "5487",
"data": {
"A": {
"31": {
"name": "NoFile"
},
"32": {
"name": " -- "
}
},
"B": {
"40": {
"label": "Label",
"description": "Error1"
},
"41": {
"label": " Data collection ",
"description": "error"
}
},
"C": {
"4": {
"description": "High problem"
},
"7": {
"description": " Normal"
}
}
}
}
]
}
"Expected_output": {
"A": {
"name" :"NoFile",
"code" : "31"
},
"B":{
"label" : "Label",
"description" : "Error1",
"code" : "40"
},
"C": {
"description" : "Normal",
"code" : "7"
}
}
$arrayElemAt to get first element from dic array
$objectToArray convert A object to array
$reduce to iterate loop of element above converted array and check condition if _id.A matches with data A then return specific field,
do the same process for B and C
db.collection.aggregate([
{
$addFields: {
dic: { $arrayElemAt: ["$dic", 0] }
}
},
{
$project: {
_id: 1,
dic: {
A: {
$reduce: {
input: { $objectToArray: "$dic.data.A" },
initialValue: "Not Found",
in: {
$cond: [
{ $eq: ["$$this.k", "$_id.A"] },
"$$this.v.name",
"$$value"
]
}
}
},
B: {
$reduce: {
input: { $objectToArray: "$dic.data.B" },
initialValue: "Not Found",
in: {
$cond: [
{ $eq: ["$$this.k", "$_id.B"] },
"$$this.v.description",
"$$value"
]
}
}
},
C: {
$reduce: {
input: { $objectToArray: "$dic.data.C" },
initialValue: "Not Found",
in: {
$cond: [
{ $eq: ["$$this.k", "$_id.C"] },
"$$this.v.description",
"$$value"
]
}
}
}
}
}
}
])
Playground

Normalize the Multiple document to single document in MongoDB

{
"_id": "null",
"data": [
{
"name": "abc",
"id": "123"
},
{
"name": "xzy",
"id": "123"
}
]
}
Explanation: the name value will become an object name. also want to convert it into one single document, that contains all the objects. abc and xyz is dynamically coming as a parameter.
Expected Output.
{
"data": {
"abc": {
"name": "abc",
"id": "100"
},
"xyz": {
"name": "xzy",
"id": "123"
}
}
}
Try this:
db.testCollection.aggregate([
{
$project: {
"array": {
$map: {
input: "$data",
as: "item",
in: {
k: "$$item.name",
v: {
"name": "$$item.id",
"id": "$$item.name"
}
}
}
}
}
},
{ $unwind: "$array" },
{
$group: {
_id: "$null",
"data": { $push: "$array" }
}
},
{
$project: {
"data": { $arrayToObject: "$data" }
}
}
]);

Mongo DB $look up Method for Fields in Arrays instead of Collections

I have a user document with the following structure:
{
"_id": {
"$oid": "5e636c552b872f00178033bf"
},
"finance": {
"expenditure": [
{
"status": true,
"_id": {
"$oid": "5e636d442b872f00178033d4"
},
"amount": {
"$numberInt": "900"
},
"category": "Coffee"
},
{
"status": true,
"_id": {
"$oid": "5e636d492b872f00178033d5"
},
"amount": {
"$numberInt": "1000"
},
"category": "Coffee"
},
{
"status": true,
"_id": {
"$oid": "5e636d532b872f00178033d6"
},
"amount": {
"$numberInt": "3000"
},
"category": "Sport"
},
{
"status": true,
"_id": {
"$oid": "5e636d572b872f00178033d7"
},
"amount": {
"$numberInt": "1000"
},
"category": "Sport"
},
],
"customcategories": [
{
"budget": {
"$numberInt": "200"
},
"_id": {
"$oid": "5e636c552b872f00178033c7"
},
"title": "Sport"
},
{
"budget": {
"$numberInt": "100"
},
"_id": {
"$oid": "5e636c552b872f00178033c8"
},
"title": "Coffee"
}
]
}
}
My previos command is this one (you don't have to mind the status and the currentdate) :
User.aggregate([
{
$match: {
_id: req.user._id
}
},
{
$unwind: "$finance.expenditure"
},
{
$match: {
"finance.expenditure.status": true
}
},
{
$sort: {
"finance.expenditure.currentdate": -1
}
},
{
$group: {
_id: "$finance.expenditure.category",
amount: {
$sum: "$finance.expenditure.amount",
}
}
},
{
$project: {
_id: 0,
category: "$_id",
amount: 1
}
}
])
The Result looks like this :
{
"expenditure": [
{
"amount": 1900,
"category": "Coffee"
},
{
"amount": 4000,
"category": "Sport"
}
]
}
I would like to add the my grouped elements the budget from the associated "customcategory".
So that it looks like this :
{
"expenditure": [
{
"amount": 1900,
"category": "Coffee",
"budget" : 100
},
{
"amount": 4000,
"category": "Sport",
"budget" : 200
}
]
}
I tried several things but nothing works of the $lookup method worked for me.
I hope some can help me :)
give this pipeline a try:
db.collection.aggregate([
{
$match: { _id: ObjectId("5e636c552b872f00178033bf") }
},
{
$unwind: "$finance.expenditure"
},
{
$match: { "finance.expenditure.status": true }
},
{
$sort: { "finance.expenditure.currentdate": -1 }
},
{
$group: {
_id: "$finance.expenditure.category",
amount: { $sum: "$finance.expenditure.amount"},
categories: { $first: '$finance.customcategories' }
}
},
{
$project: {
_id: 0,
category: "$_id",
amount: 1,
budget: {
$arrayElemAt: [
{
$map: {
input: {
$filter: {
input: '$categories',
cond: { $eq: ['$$this.title', '$_id'] }
}
},
in: '$$this.budget'
}
},
0
]
}
}
}
])
https://mongoplayground.net/p/adsWInz3wgY
Try this one:
User.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId(req.user._id)
}
},
{
$sort: {
"finance.expenditure.currentdate": -1
}
},
{
$unwind: "$finance.expenditure"
},
{
$unwind: "$finance.customcategories"
},
{
$match: {
"finance.expenditure.status": true
}
},
{
$group: {
_id: "$finance.expenditure.category",
amount: {
$addToSet: "$finance.expenditure"
},
customcategories: {
$addToSet: "$finance.customcategories"
}
}
},
{
$project: {
_id: 0,
"amount": {
$sum: "$amount.amount"
},
"category": "$_id",
"budget": {
$sum: {
$let: {
vars: {
budget: {
$filter: {
input: "$customcategories",
cond: {
$eq: [
"$_id",
"$$this.title"
]
}
}
}
},
in: "$$budget.budget"
}
}
}
}
}
])
//.exec(function(err, result){})
MongoPlayground

Resources