3rd level nesting lookup rewind at level3 in mongodb - mongodb

I have to add permissions data at each level by getting data(permission object) by permision_id from the permissions collection
at lease one level will contain permission_id and at most 3 levels can have permission_id
Sample Data looks like
{
"name": "label 1",
"permision_id": "1",
"level2": [
{
"name": "label 2.1",
"permision_id": "2",
"level3": [
{
"name": "lebel 3.1",
"permision_id": "8"
},
{
"name": "lebel 3.2",
"permision_id": "6"
}
]
},
{
"name": "label 2.2",
"permision_id": "5"
}
]
}
what I have tried
[
{
'$lookup': {
'from': 'permissions',
'localField': 'permission_id',
'foreignField': '_id',
'as': 'permissions'
}
}, {
'$unwind': {
'path': '$permissions',
'preserveNullAndEmptyArrays': true
}
}, {
'$unwind': {
'path': '$level2',
'preserveNullAndEmptyArrays': true
}
}, {
'$lookup': {
'from': 'permissions',
'let': {
'level2_permission_id': '$level2.permissions_id'
},
'pipeline': [
{
'$match': {
'$expr': {
'$eq': [
'$_id', '$$level2_permission_id'
]
}
}
}
],
'as': 'level2.permissions'
}
}, {
'$unwind': {
'path': '$level2.permissions',
'preserveNullAndEmptyArrays': true
}
}, {
'$unwind': {
'path': '$level2.level3',
'preserveNullAndEmptyArrays': true
}
}, {
'$lookup': {
'from': 'permissions',
'let': {
'level3_permission_id': '$level2.level3.permission_id'
},
'pipeline': [
{
'$match': {
'$expr': {
'$eq': [
'$_id', '$$level3_permission_id'
]
}
}
}
],
'as': 'level2.level3.permissions'
}
}, {
'$unwind': {
'path': '$level2.level3.permissions',
'preserveNullAndEmptyArrays': true
}
},{
'$group': {
'_id': '$_id',
'level2': {
'$push': '$level2'
}
}
}
]
Now the problem is level2 data is pushedd as an array at level1 correctly but I am unable to push level3 data to level2.
Output i got
{
"name": "label 1",
"permision_id": "1",
"permissions": {
"access": true,
"otherPermission": {...}
}
"level2": [
{
"name": "label 2.1",
"permision_id": "2",
"permissions": {
"access": true,
"otherPermission": {...}
}
"level3": {
"permision_id": "8"
"permissions": {
"access": true,
"otherPermission": {...}
}
}
},
{
"name": "label 2.2",
"permision_id": "5"
"permissions": {
"access": true,
"otherPermission": {...}
}
}
]
}
Output Expected at level 2 (level will reamins same)
at level 3 should be array of items with
"level2": [
{
"name": "label 2.1",
"permision_id": "2",
"permissions": {
"access": true,
"otherPermission": {...}
}
"level3": [
{
"name": "lebel 3.1",
"permision_id": "8"
"permissions": {
"access": true,
"otherPermission": {...}
}
},
{
"name": "lebel 3.2",
"permision_id": "6"
"permissions": {
"access": true,
"otherPermission": {...}
}
}
]
},
{
"name": "label 2.2",
"permision_id": "5"
"permissions": {
"access": true,
"otherPermission": {...}
}
}
]

Related

how to update nested doc in mongo

I need to batch update cdi_tags with md5 collection(push item to cdi_tags) as follows:
db.getCollection("event").update({
"_id": {
$in: [ObjectId("6368f03e21b1ad246c84d67b"), ObjectId("6368f03f21b1ad246c84d982")]
},
"meta": {
$elemMatch: {
"key": "bags",
"value"
}
}
}, {
$addToSet: {
"meta.$.value.$[t].cdi_tags: "test_tag"
}
}, {
arrayFilters: [{
"t": {
$in: ["cc09ab29db36f85e154d2c1ae9517f57", "b6b9c266f584191b6eb2d2659948a7a9"]
}
}],
multi: true
})
but not work, my doc as follows
{
"_id": ObjectId("6368f03f21b1ad246c84d982"),
"event_key": "PLAA7-194710",
"data_source": "EAP",
"name": "EP33L-AA94710",
"production": "CP",
"meta":
[
{
"key": "auto_note",
"value":
[]
},
{
"key": "bags",
"value":
{
"cc09ab29db36f85e154d2c1ae9517f57":
{
"name": "PLAA63952_event_ftp_pcar_event_20221107-194709_0.bag",
"profile": "msquare-prediction-ro",
"md5": "cc09ab29db36f85e154d2c1ae9517f57",
"cdi_tags":
[
"FDI_V1_0_0",
"from_dpp",
"epl-no-sensor",
"with_f100",
"epl-fix_video",
"epl-fix_horizon"
]
},
"361f5160cca3c3dec90cbbf93e3d7ae3":
{
"name": "PLAA63952_event_ftp_pcar_event_20221107-194709_0.bag",
"profile": "msquare-prediction-ro",
"md5": "361f5160cca3c3dec90cbbf93e3d7ae3",
"cdi_tags":
[
"FDI_V1_0_0",
"china",
"ftp_epcar_rawdata",
"from_dpp",
"trigger_type:system"
]
}
}
}
]
}
thinks
how to batch update nested doc in mongo

Mongodb aggregation nested lookup

I have 3 collections as follows:
GroupRoles Collection:
//1
{
"_id": ObjectId("62a384ee0c4dbafc64000fba"),
"name": "GroupRole template 1",
"groupRoles": [
{
"_id": ObjectId("6298503f8a31000024002107"),
"members": [
ObjectId("629e1bb117366c39bc7d78e1")
]
},
{
"_id": ObjectId("629850368a31000024002106"),
"members": [
ObjectId("629ee6d502877d0f93f5dabe"),
ObjectId("629ee6d002877d0f93f5dab8")
]
},
{
"_id": ObjectId("6298502f8a31000024002105"),
"members": [ ]
},
{
"_id": ObjectId("629850288a31000024002104"),
"members": [ ]
},
{
"_id": ObjectId("6298501f8a31000024002103"),
"members": [ ]
},
{
"_id": ObjectId("629850128a31000024002102"),
"members": [ ]
}
]
}
Role Collections:
// 1 {"_id": ObjectId("629850128a31000024002102"), "type": 1, "name": "Role 1",}
// 2 {"_id": ObjectId("6298501f8a31000024002103"), "type": 1, "name": "Role 2",}
// 3 {"_id": ObjectId("629850288a31000024002104"), "type": 1, "name": "Role 3",}
// 4 {"_id": ObjectId("6298502f8a31000024002105"), "type": 1, "name": "Role 4",}
// 5 {"_id": ObjectId("629850368a31000024002106"), "type": 1, "name": "Role 5",}
// 6 {"_id": ObjectId("6298503f8a31000024002107"), "type": 1, "name": "Role 6",}
and User Collection:
// 1 {"_id": ObjectId("629e1bb117366c39bc7d78e1"), "email": "abc1#gmail.com", "name": "user 01"}
// 2 {"_id": ObjectId("629ee6d502877d0f93f5dabe"), "email": "abc2#gmail.com", "name": "user 02"}
// 3 {"_id": ObjectId("629ee6d002877d0f93f5dab8"), "email": "abc3#gmail.com", "name": "user 03"}
How can select GroupRoles with output format like this:
{
"_id": ObjectId("62a384ee0c4dbafc64000fba"),
"name": "GroupRole template 1",
"groupRoles": [
{
"_id": ObjectId("6298503f8a31000024002107"),
"type": 1,
"name": "Role 6",
"members": [
{
"_id": ObjectId("629e1bb117366c39bc7d78e1"),
"email": "abc1#gmail.com",
"name": "user 01"
}
]
},
{
"_id": ObjectId("629850368a31000024002106"),
"type": 1,
"name": "Role 5",
"members": [
{
"_id": ObjectId("629ee6d502877d0f93f5dabe"),
"email": "abc2#gmail.com",
"name": "user 02"
},
{
"_id": ObjectId("629ee6d002877d0f93f5dab8"),
"email": "abc3#gmail.com",
"name": "user 03"
}
]
},
{
"_id": ObjectId("6298502f8a31000024002105"),
"type": 1,
"name": "Role 4",
"members": [ ]
},
{
"_id": ObjectId("629850288a31000024002104"),
"type": 1,
"name": "Role 3",
"members": [ ]
},
{
"_id": ObjectId("6298501f8a31000024002103"),
"type": 1,
"name": "Role 2",
"members": [ ]
},
{
"_id": ObjectId("629850128a31000024002102"),
"type": 1,
"name": "Role 1",
"members": [ ]
}
]
}
I've tried aggregation and lookup, but it didn't get the results I wanted.
here is my aggregation query
The list of members is not in the correct index of groupRoles
[
{
'$lookup': {
'from': 'roles',
'localField': 'groupRoles._id',
'foreignField': '_id',
'as': 'temp_roles'
}
}, {
'$lookup': {
'from': 'users',
'localField': 'groupRoles.members',
'foreignField': '_id',
'as': 'temp_users'
}
}, {
'$addFields': {
'groupRoles': {
'$map': {
'input': '$groupRoles.members',
'as': 'mems',
'in': {
'members': {
'$filter': {
'input': '$temp_users',
'as': 'temu',
'cond': {
'$in': [
'$$temu._id', '$$mems'
]
}
}
}
}
}
}
}
}, {
'$addFields': {
'groupRoles': {
'$map': {
'input': {
'$zip': {
'inputs': [
'$groupRoles', '$temp_roles'
]
}
},
'in': {
'$mergeObjects': '$$this'
}
}
}
}
}, {
'$unset': [
'temp_roles', 'temp_users'
]
}, {
'$facet': {
'metadata': [
{
'$group': {
'_id': null,
'total': {
'$sum': 1
}
}
}
],
'data': []
}
}, {
'$project': {
'data': {
'_id': 1,
'name': 1,
'groupRoles': {
'_id': 1,
'type': 1,
'name': 1,
'members': {
'_id': 1,
'name': 1,
'email': 1
}
}
},
'total': {
'$arrayElemAt': [
'$metadata.total', 0
]
}
}
}
]
please help me find the solution.
Revise your query and thanks for the hints.
The issue is on $zip, which I think this operator is not suitable. You can check the behavior of $zip.
Combine both $addFields stages into one.
Iterate each value in groupRoles and with $mergeObjects for
Current iterate value.
The first match document from the temp_roles array by matching _id.
The document with members array.
db.groupRoles.aggregate([
{
"$lookup": {
"from": "roles",
"localField": "groupRoles._id",
"foreignField": "_id",
"as": "temp_roles"
}
},
{
"$lookup": {
"from": "users",
"localField": "groupRoles.members",
"foreignField": "_id",
"as": "temp_users"
}
},
{
"$addFields": {
"groupRoles": {
"$map": {
"input": "$groupRoles",
"as": "gr",
"in": {
"$mergeObjects": [
"$$gr",
{
$first: {
"$filter": {
"input": "$temp_roles",
"as": "r",
"cond": {
$eq: [
"$$gr._id",
"$$r._id"
]
}
}
}
},
{
"members": {
"$filter": {
"input": "$temp_users",
"as": "mem",
"cond": {
"$in": [
"$$mem._id",
"$$gr.members"
]
}
}
}
}
]
}
}
}
}
},
{
"$unset": [
"temp_roles",
"temp_users"
]
},
])
Sample Mongo Playground

MongoDB query to include count of most frequent values for multiple fields

Thank you in advance for any help!
I've a collection QR with schema similar to this:
var qrSchema = new Schema({
qrId: { type: String, index: true },
owner: { type: Schema.Types.ObjectId, ref: 'User' },
qrName: { type: String },
qrCategory: { type: String, index: true },
shortUrl: { type: String}}
})
And collection Datas similar to this:
var dataSchema = new Schema({
qrId: { type: String, index: true}
city: { type: String},
device: { type: String},
date: { type: Date, index:true},
})
The relation between QR and Datas is 1-to-many.
I've an aggregate like this:
Model.QR.aggregate([
{ $match: {
$and: [
{ owner: mongoose.Types.ObjectId(user._id) },
{
$expr: {
$cond: [
{ $in: [ category, [ null, "", "undefined" ]] },
true,
{ $eq: [ "$qrCategory", category ] }
]
}
}
]
}
},
{ $lookup:
{
"from": "datas",
"localField": "qrId",
"foreignField": "qrId",
"as": "data"
}
},
{
$project: {
_id: 0,
qrId: 1,
qrName: 1,
qrCategory: 1,
shortUrl: 1,
data: {
$filter: {
input: "$data",
as: "item",
cond: {
$and: [
{ $gte: [ "$$item.date", date.start ] },
{ $lte: [ "$$item.date", date.end ] }
] }
}
}
}
},
{
$group: {
_id: { "qrId": "$qrId", "qrName": "$qrName", "qrCategory": "$qrCategory", "shortUrl": "$shortUrl" },
data: {
$push: {
dataItems: "$data",
count: {
$size: { '$ifNull': ['$data', []] }
}
}
}
}
},
{
$sort: {
"data.count": -1
}
},
{
$limit: 10,
}]).exec((err, results) => { })
Which is returning something like:
[
{
"_id": {
"qrId": "0PRA",
"qrName": "Campaign 0PRA",
"qrCategory": "html",
"shortUrl": "http://someurl.com/0PRA"
},
"data": [
{
"dataItems": [
{
"_id": "6200f2a8c0cf7a1c49233c7f",
"qrId": "0PRA",
"device": "iOS",
"city": "Beijing",
},
{
"_id": "6200f2eac0cf7a1c49233c80",
"qrId": "0PRA",
"device": "AndroidOS",
"city": "Beijing",
},
{
"_id": "6200f3a4c0cf7a1c49233c81",
"qrId": "0PRA",
"device": "AndroidOS",
"city": "Beijing",
},
{
"_id": "6200f632c0cf7a1c49233c88",
"qrId": "0PRA",
"device": "AndroidOS",
"city": "Nanchang",
},
{
"_id": "6201b342c0cf7a1c49233caa",
"qrId": "0PRA",
"device": "iOS",
"city": "Taizhou",
}
],
"count": 5
}
]
},
{
"_id": {
"qrId": "NQ17",
"qrName": "Campaign NQ17",
"qrCategory": "menu",
"shortUrl": "http://someurl.com/NQ17"
},
"data": [
{
"dataItems": [
{
"_id": "6200f207c0cf7a1c49233c7a",
"qrId": "NQ17",
"device": "iOS",
"city": "Singapore"
},
{
"_id": "8200f207c1cf7a1c49233c7a",
"qrId": "NQ17",
"device": "iOS",
"city": "Singapore"
},
{
"_id": "6200ac5db44f23b9ec2b6040",
"qrId": "NQ17",
"device": "AndroidOS",
"city": "San Antonio"
}
],
"count": 3
}
]
}
]
I'm trying to include the most frequent device and city in the results after the count of dataItems, like this:
[
{
"_id": {
"qrId": "0PRA",
"qrName": "Campaign 0PRA",
"qrCategory": "html",
"shortUrl": "http://someurl.com/0PRA"
},
"data": [
{
"dataItems": [
{
"_id": "6200f2a8c0cf7a1c49233c7f",
"qrId": "0PRA",
"device": "iOS",
"city": "Beijing",
},
{
"_id": "6200f2eac0cf7a1c49233c80",
"qrId": "0PRA",
"device": "AndroidOS",
"city": "Beijing",
},
{
"_id": "6200f3a4c0cf7a1c49233c81",
"qrId": "0PRA",
"device": "AndroidOS",
"city": "Beijing",
},
{
"_id": "6200f632c0cf7a1c49233c88",
"qrId": "0PRA",
"device": "AndroidOS",
"city": "Nanchang",
},
{
"_id": "6201b342c0cf7a1c49233caa",
"qrId": "0PRA",
"device": "iOS",
"city": "Taizhou",
}
],
"count": 5,
"topDevice": "AndroidOS", // <---- trying to add this
"topLocation": "Beijing" // <---- trying to add this
}
]
},
{
"_id": {
"qrId": "NQ17",
"qrName": "Campaign NQ17",
"qrCategory": "menu",
"shortUrl": "http://someurl.com/NQ17"
},
"data": [
{
"dataItems": [
{
"_id": "6200f207c0cf7a1c49233c7a",
"qrId": "NQ17",
"device": "iOS",
"city": "Singapore"
},
{
"_id": "8200f207c1cf7a1c49233c7a",
"qrId": "NQ17",
"device": "iOS",
"city": "Singapore"
},
{
"_id": "6200ac5db44f23b9ec2b6040",
"qrId": "NQ17",
"device": "android",
"city": "San Antonio"
}
],
"count": 3,
"topDevice": "iOS", // <---- trying to add this
"topLocation": "Singapore" // <---- trying to add this
}
]
}
]
Is this possible?
Thank you very much in advance for any help or hints!
Method 1
Use $function will be way more easier. MongoDB version >= 4.4
Sort function in js
db.collection.aggregate([
{
"$set": {
"data": {
"$map": {
"input": "$data",
"as": "d",
"in": {
"count": "$$d.count",
"dataItems": "$$d.dataItems",
"topDevice": {
$function: {
body: "function(arr) {return arr.sort((a,b) =>arr.filter(v => v===a).length-arr.filter(v => v===b).length).pop() }",
args: [ "$$d.dataItems.device" ],
lang: "js"
}
},
"topLocation": {
$function: {
body: "function(arr) {return arr.sort((a,b) =>arr.filter(v => v===a).length-arr.filter(v => v===b).length).pop() }",
args: [ "$$d.dataItems.city" ],
lang: "js"
}
}
}
}
}
}
}
])
mongoplayground
Method 2
db.qr.aggregate([
{
"$match": {
owner: {
"$in": [
"1",
"2"
]
}
}
},
{
"$lookup": {
"from": "data",
"localField": "qrId",
"foreignField": "qrId",
"as": "data",
"pipeline": [
{
"$match": {
"$and": [
{
"date": {
"$gte": ISODate("2021-09-01T01:23:25.184Z")
}
},
{
"date": {
"$lte": ISODate("2021-09-02T11:23:25.184Z")
}
}
]
}
},
{
"$facet": {
"deviceGroup": [
{
"$group": {
"_id": "$device",
"sum": {
"$sum": 1
}
}
},
{
"$sort": {
sum: -1
}
},
{
"$limit": 1
}
],
"cityGroup": [
{
"$group": {
"_id": "$city",
"sum": {
"$sum": 1
}
}
},
{
"$sort": {
sum: -1
}
},
{
"$limit": 1
}
],
"all": []
}
}
]
}
},
{
"$set": {
"data": {
"$first": "$data.all"
},
"topDevice": {
"$first": {
"$first": "$data.deviceGroup._id"
}
},
"topLocation": {
"$first": {
"$first": "$data.cityGroup._id"
}
}
}
},
{
$group: {
_id: {
"qrId": "$qrId",
"qrName": "$qrName",
"qrCategory": "$qrCategory",
"shortUrl": "$shortUrl"
},
data: {
$push: {
dataItems: "$data",
topDevice: "$topDevice",
topLocation: "$topLocation",
count: {
$size: {
"$ifNull": [
"$data",
[]
]
}
}
}
}
}
}
])
mongoplayground
Query
add the match you need, i didn't understand what the match should do
lookup on qrId
filter to keep only the start<=dates<=end (replace the 1 and 100)
facet to group all-documents, the topDevice the topLocation
$set to bring those data out from the nested locations they are
count is added as the size of all-documents
*maybe i am missing something, but try it(first part i think its like YuTing answer)
Test code here
QR.aggregate(
[{"$lookup":
{"from":"Datas",
"localField":"qrId",
"foreignField":"qrId",
"pipeline":
[{"$match":{"$and":[{"date":{"$gte":1}}, {"date":{"$lte":100}}]}},
{"$facet":
{"dataItems":[],
"topDevice":
[{"$group":{"_id":"$device", "count":{"$sum":1}}},
{"$sort":{"count":-1}}, {"$limit":1}],
"topLocation":
[{"$group":{"_id":"$city", "count":{"$sum":1}}},
{"$sort":{"count":-1}}, {"$limit":1}]}}],
"as":"data"}},
{"$set":{"data":{"$arrayElemAt":["$data", 0]}}},
{"$set":
{"dataItems":"$data.dataItems",
"count":{"$size":"$data.dataItems"},
"topDevice":
{"$getField":
{"field":"_id", "input":{"$arrayElemAt":["$data.topDevice", 0]}}},
"topLocation":
{"$getField":
{"field":"_id",
"input":{"$arrayElemAt":["$data.topLocation", 0]}}},
"data":"$$REMOVE"}}])

Merge documents from 2 collections in MongoDB & preserve property of a field

I have two collections, 1. temporaryCollection, 2. permanentCollection, I would like to take data from temporaryCollection and update in permanentCollection. To see the expected result see updatedPermanentCollection below.
Fields that are taken from Temporary collection and updated in Permanent collection are:
emailAddresses
phoneNumbers
ContactName
ContactNumber
For your info, the fields that are changed in Temporary collection
contacts[0]['emailAddresses']
contacts[0]['ContactName']
contacts[0]["phoneNumbers"]
contacts[0]["ContactNumber"]
Field that are that should not be changed after updation in UpdatedPermanentCollection is
contacts._id
Note: contacts is an Array of objects, for simplicity I have shown just one object.
I am currently using the below query which updates the permanentCollection but also overrides the contacts._id field. I don't want the contacts._id field to be overridden.
Here is my MongoDB Query
db.temporaryCollection.aggregate([
{
$match: {
userID: ObjectId("61d1efea2c0fab00340f47c8"),
},
},
{
$merge: {
into: "permanentCollection",
on: "userID",
whenMatched: "merge",
whenNotMatched: "insert",
},
},
]);
1. temporaryCollection
{
"_id": { "$oid": "61d1f04266289f003452d705" },
"userID": { "$oid": "61d1efea2c0fab00340f47c8" },
"contacts": [
{
"emailAddresses": [
{ "id": "6884", "label": "email1", "email": "addedemail#gmail.com" }
],
"phoneNumbers": [
{
"label": "other",
"id": "4594",
"number": "+918984292930"
},
{
"label": "other",
"id": "4595",
"number": "+911234567890"
}
],
"_id": { "$oid": "61d1f04266289f003452d744" },
"ContactName": "Sample User 1 Name Changed",
"ContactNumber": "+918984292930",
"recordID": "833"
}
],
"userNumber": "+911234567890",
"__v": 7
}
2. permanentCollection
{
"_id": { "$oid": "61d1f04266289f003452d701" },
"userID": { "$oid": "61d1efea2c0fab00340f47c8" },
"contacts": [
{
"emailAddresses": [],
"phoneNumbers": [
{
"label": "other",
"id": "4594",
"number": "+918984292929"
},
{
"label": "other",
"id": "4595",
"number": "+911234567890"
}
],
"_id": { "$oid": "61d1f04266289f003452d722" },
"ContactName": "Sample User 1",
"ContactNumber": "+918984292929",
"recordID": "833"
}
],
"userNumber": "+911234567890",
"__v": 7
}
3. updatedPermanentCollection (Expected result)
{
"_id": { "$oid": "61d1f04266289f003452d701" },
"userID": { "$oid": "61d1efea2c0fab00340f47c8" },
"contacts": [
{
"emailAddresses": [
{ "id": "6884", "label": "email1", "email": "addedemail#gmail.com" }
],
"phoneNumbers": [
{
"label": "other",
"id": "4594",
"number": "+918984292930"
},
{
"label": "other",
"id": "4595",
"number": "+911234567890"
}
],
"_id": { "$oid": "61d1f04266289f003452d722" },
"ContactName": "Sample User 1 Name Changed",
"ContactNumber": "+918984292930",
"recordID": "833"
}
],
"userNumber": "+911234567890",
"__v": 7
}
Try with this aggregation query.
db.temporarCollection.aggreagate(
[
{
"$lookup": {
"from": "permanantCollection",
"let": {
"user_id": "$userID"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$$user_id", "$userID"
]
}
}
}
],
"as": "pcontacts"
}
}, {
"$unwind": {
"path": "$pcontacts",
"preserveNullAndEmptyArrays": true
}
}, {
"$project": {
"contacts": {
"$map": {
"input": "$contacts",
"as": "contact",
"in": {
"tcontact": "$$contact",
"pcontact": {
"$first": {
"$filter": {
"input": "$pcontacts.contacts",
"as": "pcontact",
"cond": {
"$eq": [
"$$pcontact.recordID", "$$contact.recordID"
]
}
}
}
}
}
}
},
"userNumber": 1,
"userID": 1,
"_id": 0
}
}, {
"$project": {
"contacts": {
"$map": {
"input": "$contacts",
"as": "contact",
"in": {
"emailAddresses": "$$contact.tcontact.emailAddresses",
"phoneNumbers": "$$contact.tcontact.phoneNumbers",
"ContactName": "$$contact.tcontact.ContactName",
"ContactNumber": "$$contact.tcontact.ContactNumber",
"recordID": {
"$let": {
"vars": {},
"in": {
"$cond": {
"if": "$$contact.pcontact.recordID",
"then": "$$contact.pcontact.recordID",
"else": "$$contact.tcontact.recordID"
}
}
}
},
"_id": {
"$let": {
"vars": {},
"in": {
"$cond": {
"if": "$$contact.pcontact._id",
"then": "$$contact.pcontact._id",
"else": "$$contact.tcontact._id"
}
}
}
}
}
}
},
"userNumber": 1,
"userID": 1
}
}, {
"$merge": {
"into": "pc",
"on": "userID",
"whenMatched": "replace",
"whenNotMatched": "insert"
}
}
])
It is not a fully optimized query but it works.
Try to add $unset to db query.
db.temporaryCollection.aggregate([
{
$unset: "_id"
},
{
$match: {
userID: ObjectId("61d1efea2c0fab00340f47c8"),
},
},
{
$merge: {
into: "permanentCollection",
on: "userID",
whenMatched: "merge",
whenNotMatched: "insert",
},
},
]);

mongodb aggregate lookup with a query

I have collections with following values:
reports
{
"_id": { "$oid": "5f05e1d13e0f6637739e215b" },
"testReport": [
{
"name": "Calcium",
"value": "87",
"slug": "ca",
"details": {
"description": "description....",
"recommendation": "recommendation....",
"isNormal": false
}
},
{
"name": "Magnesium",
"value": "-98",
"slug": "mg",
"details": {
"description": "description....",
"recommendation": "recommendation....",
"isNormal": false
}
}
],
"patientName": "Patient Name",
"clinicName": "Clinic",
"gender": "Male",
"bloodGroup": "A",
"createdAt": { "$date": "2020-07-08T15:10:09.612Z" },
"updatedAt": { "$date": "2020-07-08T15:10:09.612Z" }
},
setups
{
"_id": { "$oid": "5efcba7503f4693d164e651d" },
"code": "Ca",
"codeLower": "ca",
"name": "Calcium",
"valueFrom": -75,
"valueTo": -51,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
},
{
"_id": { "$oid": "5efcba7503f4693d164e651e" }, // <=== should find this for Calcium
"code": "Ca",
"codeLower": "ca",
"name": "Calcium",
"valueFrom": 76,
"valueTo": 100,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
},
{
"_id": { "$oid": "5efcba7603f4693d164e65bb" }, // <=== should find this for Magnesium
"code": "Mg",
"codeLower": "mg",
"name": "Magnesium",
"valueFrom": -100,
"valueTo": -76,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
},
{
"_id": { "$oid": "5efcba7503f4693d164e6550" },
"code": "Mg",
"codeLower": "mg",
"name": "Magnesium",
"valueFrom": 76,
"valueTo": 100,
"treatmentDescription": "description...",
"isNormal": false,
"gender": "",
"recommendation": "recommendation...",
"createdAt": { "$date": "2020-07-01T16:31:50.205Z" },
"updatedAt": { "$date": "2020-07-01T16:31:50.205Z" }
}
I want to search the value from reports collection and check whether the value is in range from the setups collection and return the _id and add the returned _ids in setupIds field on reports collection.
I tried with the following aggregation framework:
db.reports.aggegrate([
{
'$match': {
'_id': new ObjectId('5f05e1d13e0f6637739e215b')
}
}, {
'$lookup': {
'from': 'setups',
'let': {
'testValue': '$testReport.value',
'testName': '$testReport.name'
},
'pipeline': [
{
'$match': {
'$expr': {
{
'$and': [
{
'$eq': [
'$name', '$$testName'
]
}, {
'$gte': [
'$valueTo', '$$testValue'
]
}, {
'$lte': [
'$valueFrom', '$$testValue'
]
}
]
}
}
}
}
],
'as': 'setupIds'
}
}
])
This query didn't find the expected results.
This is the updated reports collection I want:
{
"_id": { "$oid": "5f05e1d13e0f6637739e215b" },
"setupIds": [{ "$oid": "5efcba7503f4693d164e651e" }, { "$oid": "5efcba7603f4693d164e65bb" }], // <=== Here, array of the ObjectId (ref: "Setups")
"patientName": "Patient Name",
"clinicName": "Clinic",
"gender": "Male",
"bloodGroup": "A",
"createdAt": { "$date": "2020-07-08T15:10:09.612Z" },
"updatedAt": { "$date": "2020-07-08T15:10:09.612Z" }
},
You can try like following
[{
$match: {
_id: ObjectId('5f05e1d13e0f6637739e215b')
}
}, {
$unwind: {
path: "$testReport"
}
}, {
$lookup: {
from: 'setup',
'let': {
testValue: {
$toInt: '$testReport.value'
},
testName: '$testReport.name'
},
pipeline: [{
$match: {
$expr: {
$and: [{
"$eq": [
"$name",
"$$testName"
]
},
{
"$gte": [
"$valueTo",
"$$testValue"
]
},
{
"$lte": [
"$valueFrom",
"$$testValue"
]
}
]
}
}
}],
as: 'setupIds'
}
}, {
$group: {
_id: "$_id",
patientName: {
$first: "$patientName"
},
clinicName: {
$first: "$clinicName"
},
gender: {
$first: "$gender"
},
bloodGroup: {
$first: "$bloodGroup"
},
createdAt: {
$first: "$createdAt"
},
updatedAt: {
$first: "$updatedAt"
},
setupIds: {
$addToSet: "$setupIds._id"
}
}
}, {
$addFields: {
setupIds: {
$reduce: {
input: "$setupIds",
initialValue: [],
in: {
$setUnion: ["$$this", "$$value"]
}
}
}
}
}]
Working Mongo playground