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
Related
Need help with removing fields with empty values in array. So far, code is removing both values if one of the field is having empty value.
Example docment:
{
"_id": ObjectId("62ed3cfbeadf50344d622dd0"),
"Status": 1,
"AnswerList": [
{
"Question1": "some question1",
"Question2": "some question2",
"Answer": "",
"Comment": "Some comment"
},
{
"Question1": "some question1",
"Question2": "some question2",
"Answer": "some answer",
"Comment": ""
}
]
}
My query so far:
db.collection.aggregate([
{
$project: {
_id: 0,
Survey: 1,
Status: 1,
AnswerList: {
$map: {
input: "$AnswerList",
in: {
$cond: {
if: {
$in: [
"",
[
"$this.Comment",
"$this.Answer"
]
]
},
then: {
$arrayToObject: {
$filter: {
input: {
$map: {
input: {
$objectToArray: "$$this"
},
as: "element",
in: {
$cond: [
{
$in: [
"$$element.k",
[
"Comment",
"Answer"
]
]
},
null,
"$$element"
]
}
}
},
as: "filter",
cond: "$$filter"
}
}
},
else: "$$this"
}
}
}
}
}
}
])
One option is using $map and $filter with $arrayToObject and $objectToArray:
db.collection.aggregate([
{
$project: {
_id: 0,
Survey: 1,
Status: 1,
AnswerList: {
$map: {
input: "$AnswerList",
as: "item",
in: {$arrayToObject: {
$filter: {
input: {$objectToArray: "$$item"},
as: "pair",
cond: {$ne: ["$$pair.v", ""]}
}
}
}
}
}
}
}
])
See how it works on the playground example
Explanation:
I am using the,
"A":{ "$arrayElemAt" :[ {"$split" : ["$info_id" , "_"]},0]},
"B":{ "$arrayElemAt" :[ {"$split" : ["$info_id" , "_"]},1]},
"C":{ "$arrayElemAt" :[ {"$split" : ["$info_id" , "_"]},2]},
but if after 2nd _ nothing is there then I want the output to be as "NA".
Document 1:
"info": {
"id": "2_452_1",
},
Document 2:
"info": {
"id": "9_5",
},
Expected output Document 1:
{
"A": "2",
"B": "452",
"C": "1"
}
Expected output Document 2:
{
"A": "9",
"B": "5",
"C": "NA"
}
$split to split id string by "_"
$arrayElemAt to get specific element from above result array from split
$ifNull to check return result from the above operation is null then return "NA"
db.collection.aggregate([
{ $project: { info: { $split: ["$info.id", "_"] } } },
{
$project: {
A: {
$ifNull: [{ $arrayElemAt: ["$info", 0] }, "NA"]
},
B: {
$ifNull: [{ $arrayElemAt: ["$info", 1] }, "NA"]
},
C: {
$ifNull: [{ $arrayElemAt: ["$info", 2] }, "NA"]
}
}
}
])
Playground
{
"_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" }
}
}
]);
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
Assume I have the following document:
[
{
"callId": "17dac51e-125e-499e-9064-f20bd3b1a9d8",
"caller": {
"firstName": "Test",
"lastName": "Testing",
"phoneNumber": "1231231234"
},
"routeHistory": [
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-01T06:00:00.000Z",
"status": "routed"
},
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-03T06:00:00.000Z",
"status": "ended"
}
]
}
]
I want to get results where routeHistory.routeDate is equal to the $max routeDate value in routeHistory. I would expect my results to look like the following:
[
{
"callId": "17dac51e-125e-499e-9064-f20bd3b1a9d8",
"caller": {
"firstName": "Test",
"lastName": "Testing",
"phoneNumber": "1231231234"
},
"routeHistory": [
{
"assignedUserId": "cfa0ffe9-c77d-4eec-87d7-4430f7772e81",
"routeDate": "2020-01-03T06:00:00.000Z",
"status": "ended"
}
]
}
]
Is there a clean way to do this in a single aggregate, so that additional $match criteria can be applied?
You can use $let to define temporary variable being $max date and the use $filter along with $arrayElemAt to get first matching element:
db.collection.aggregate([
{
$addFields: {
routeHistory: {
$let: {
vars: {
maxDate: { $max: "$routeHistory.routeDate" }
},
in: {
$arrayElemAt: [
{ $filter: { input: "$routeHistory", cond: { $eq: [ "$$maxDate", "$$this.routeDate" ] } } },
0
]
}
}
}
}
}
])
Mongo Playground
EDIT:
version without $let:
db.collection.aggregate([
{
$addFields: {
maxDate: {
$max: "$routeHistory.routeDate"
}
}
},
{
$addFields: {
routeHistory: {
$arrayElemAt: [
{
$filter: { input: "$routeHistory", cond: { $eq: [ "$$maxDate", "$$this.routeDate" ] } }
},
0
]
}
}
}
}
])