How can get particular object data from double nested array in mongodb - mongodb

i m new in mongodb, i want only single object data which id is 5689746, by which way can i get this?
[
{
"_id": 8965651651,
"orditems": [
{
"_id": 65748413141,
"itms": [
{
"item1": "aa",
"item2": "bb",
"item3": "cc",
"_id": 7894567
},
{
"item1": "dd",
"item2": "ee",
"item3": "ff",
"_id": 5689746
},
{
"item1": "gg",
"item2": "hh",
"item3": "ii",
"_id": 1644824
}
]
},
{
"_id": 87448413141,
"itms": [
{
"item1": "jj",
"item2": "kk",
"item3": "ll",
"_id": 9874567
},
{
"item1": "mm",
"item2": "nn",
"item3": "oo",
"_id": 8659746
},
{
"item1": "pp",
"item2": "qq",
"item3": "rr",
"_id": 4614824
}
]
}
]
}
]
i m using $elemMatch but i didn't get result as expected
db.orders.findOne({
_id: 8965651651
},
{
orditems: {
$elemMatch: {
_id: 87448413141,
itms: {
$elemMatch: {
_id: 5689746
}
}
}
}
})
i want result like
{
"_id": 8965651651,
"orditems": [
{
"_id": 65748413141,
"itms": [
{
"item1": "dd",
"item2": "ee",
"item3": "ff",
"_id": 5689746
}
]
}
]
}

You need to chain up $filter and $mergeObjects as you are doubly nesting your array fields.
db.collection.aggregate([
{
$match: {
"_id": 8965651651
}
},
{
$set: {
orditems: {
"$filter": {
"input": "$orditems",
"as": "oi",
"cond": {
$eq: [
"$$oi._id",
65748413141
]
}
}
}
}
},
{
$set: {
orditems: {
"$map": {
"input": "$orditems",
"as": "oi",
"in": {
"$mergeObjects": [
"$$oi",
{
itms: {
"$filter": {
"input": "$$oi.itms",
"as": "i",
"cond": {
$eq: [
"$$i._id",
5689746
]
}
}
}
}
]
}
}
}
}
}
])
Mongo Playground

Related

MongoDB. Get every element from array in new field

I have a document with a nested array array_field:
{
"_id": {
"$oid": "1"
},
"id": "1",
"array_field": [
{
"data": [
{
"regions": [
{
"result": {
"item": [
"4",
"5",
"3"
]
}
},
{
"result": {
"item": [
"5"
]
}
},
{
"result": {
"item": [
"1"
]
}
}
]
}
]
}
]
}
I need add new field, new_added_field for example, with each array element from array_field.data.regions.result.item and remove array_field from document.
For example:
{
"_id": {
"$oid": "1"
},
"id": "1",
"new_added_field": [4,5,3,5,1]
}
I think i can do this with help of $unwind or $map but have difficulties and need dome hint, how i can do it with help op aggregation?
As you said,
db.collection.aggregate([
{
"$project": {
newField: {
"$map": {
"input": "$array_field",
"as": "m",
"in": "$$m.data.regions.result.item"
}
}
},
},
{ "$unwind": "$newField" },
{ "$unwind": "$newField" },
{ "$unwind": "$newField" },
{ "$unwind": "$newField" },
{
"$group": {
"_id": "$_id",
"newField": { "$push": "$newField" }
}
}
])
Working Mongo playground

Filter and update embedded Array in mongodb mongoose

The MongoDb model looks like this :
{
"_id": {
"$oid": "5ee269c949c9d58970528d1e"
},
"parent": [
{
"_id": {
"$oid": "5ee269c949c9d58970528d1d"
},
"uType": "parent",
"fName": "p1",
"lName": "p1",
"num": "123"
}
],
"child": [
{
"_id": {
"$oid": "5ee269c949c9d58970528d1c"
},
"uType": "child",
"fName": "c1",
"lName": "c1",
"num": "8963",
"email": "c1#gmail.com",
"gender": "male"
}
]
}
I have an incoming object that looks like this -
{
"uType":"child",
"fName": "c2",
"lName": "c2",
"num": "98733",
"email": "c2#gmail.app",
"invite": {
"uType": "parent",
"fName": "p1",
"lName": "p1",
"num": "123"
}
}
I have to filter for the incoming object such that I get the response like below- which means for the incoming object, there is a matching parent but there is not a matching child.
Tried using $or and provided multiple conditions but every time ended up getting a record in child array. I gave it a shot using aggregate as well but could not find a possible solution. Can someone tell me what is the best way to do this?
{
"_id": {
"$oid": "5ee269c949c9d58970528d1e"
},
"parent": [
{
"isActive": false,
"_id": {
"$oid": "5ee269c949c9d58970528d1d"
},
"uType": "parent",
"fName": "p1",
"lName": "p1",
"num": "123"
}
],
"child": [ ]
}
UPDATE: Tried using projection, but still no luck -
Model.aggregate([
{
$project: {
child: {
$filter: {
input: "$child",
as: "ch",
cond: { $eq: ["$ch.num", this.num] }
}
}
}
}
])
Actually, you are so close to the solution, if you use "$$ch.num" instead of "$ch.num" it should work.
const match = {
"uType":"child",
"fName": "c2",
"lName": "c2",
"num": "98733",
"email": "c2#gmail.app",
"invite": {
"uType": "parent",
"fName": "p1",
"lName": "p1",
"num": "123"
}
}
Model.aggregate([
{
$match: {
$or: [
{
"parent.num": match.invite.num
},
{
"child.num": match.num
}
]
}
},
{
$project: {
parent: {
$filter: {
input: "$parent",
as: "p",
cond: {
$eq: [
"$$p.num",
match.invite.num
]
}
}
},
child: {
$filter: {
input: "$child",
as: "ch",
cond: {
$eq: [
"$$ch.num",
match.num
]
}
}
}
}
}
])
But you can do something similar without aggregation, but you will not get an empty array when there is no match, you will just don't get the key.
Model.find({
$or: [
{
"parent.num": match.invite.num
},
{
"child.num": match.num
}
]
},
{
parent: {
$elemMatch: {
num: match.invite.num
},
},
child: {
$elemMatch: {
num: match.num
}
}
})

how to create an array on the output of a response using aggregate in Mongodb

I have in my collection a list of objects with this structure:
[
{
"country": "colombia",
"city":"medellin",
"calification": [
{
"_id": 1,
"stars": 5
},
{
"_id": 2,
"stars": 3
}
]
},
{
"country": "colombia",
"city":"manizales",
"calification": [
{
"_id": 1,
"stars": 5
},
{
"_id": 2,
"stars": 5
}
]
},
{
"country": "argentina",
"city":"buenos aires",
"calification": [
{
"_id": 1,
"stars": 5
},
]
},
{
"country": "perĂº",
"city":"cusco",
"calification": [
{
"_id": 3,
"stars": 3
},
]
}
]
I am trying to make a filter so that the output is an amount of arrays for each country. this is the example of the output i want.
avg would be result sum 'stars'/ calification.length
{
"colombia": [
{
"city": "medellin",
"avg": 4,
"calification": [
{
"_id": 1,
"stars": 5
},
{
"_id": 2,
"stars": 3
}
]
},
{
"city": "manizales",
"avg": 5,
"calification": [
{
"_id": 1,
"stars": 5
},
{
"_id": 2,
"stars": 3
}
]
}
],
"argentina": {
"city": "buenos aires",
"avg": 5,
"calification": [
{
"_id": 1,
"stars": 5
}
]
},
"peru": {
"city": "cusco",
"avg": 4,
"calification": [
{
"_id": 1,
"stars": 4
}
]
}
}
I am trying to do this:
Alcalde.aggregate([
{
$addFields: {
colombia: {
"$push": {
"$cond": [{ $eq: ["$country", "'Colombia'"] }, true, null]
}
}
}
},
{
$project: { colombia: "$colombia" }
}
]
how can i do it
We can make it more elegant.
MongoDB has $avg operator, let's use it. Also, we can use $group operator to group cities for the same country.
At the end, applying $replaceRoot + $arrayToObject** we transform into desired result.
** it's because we cannot use such expression: {"$country":"$city"}
$replaceRoot $arrayToObject
data : { { [ {
"key" : "val", --> "key" : "val", {k:"key", v: "val"}, --> "key" : "val",
"key2" : "val2" "key2" : "val2" {k:"key2", v: "val2"} "key2" : "val2"
} } ] }
Try this one:
Alcalde.aggregate([
{
$group: {
_id: "$country",
city: {
$push: {
"city": "$city",
"avg": { $avg: "$calification.stars"},
"calification": "$calification"
}
}
}
},
{
$replaceRoot: {
newRoot: {
$arrayToObject: [ [{ "k": "$_id", "v": "$city"}] ]
}
}
}
])
MongoPlayground
EDIT: Generic way to populate city inner object
$$ROOT is variable which stores root document
$mergeObjects adds / override fields to final object
Alcalde.aggregate([
{
$group: {
_id: "$country",
city: {
$push: {
$mergeObjects: [
"$$ROOT",
{
"avg": { "$avg": "$calification.stars" }
}
]
}
}
}
},
{
$project: {
"city.country": 0
}
},
{
$replaceRoot: {
newRoot: {
$arrayToObject: [
[ { "k": "$_id", "v": "$city" } ]
]
}
}
}
])
MongoPlayground

Is there a way in mongodb to group at multiple levels

I have a document which contains an array of array as given below.
This is the first document.
{
"_id": "5d932a2178fdfc4dc41d75da",
"data": [
{
"nestedData": [
{
"_id": "5d932a2178fdfc4dc41d75e1",
"name": "Special 1"
},
{
"_id": "5d932a2178fdfc4dc41d75e0",
"name": "Special 2"
}
]
}
]
}
I need to lookup(join) to another collection with the _id in the nestedData array in the aggregation framework.
The 2nd document from which I need to lookup is
{
"_id": "5d8b1ac3b15bc72d154408e1",
"status": "COMPLETED",
"rating": 4
}
I know I need to $unwind it twice to convert nestedData array into object.
But how do I group back again to form the same object like given below
{
"_id": "5d932a2178fdfc4dc41d75da",
"data": [
{
"array": [
{
"_id": "5d932a2178fdfc4dc41d75e1",
"name": "Special 1",
"data": {
"_id": "5d8b1ac3b15bc72d154408e1",
"status": "COMPLETED",
"rating": 4
},
{
"_id": "5d932a2178fdfc4dc41d75e0",
"name": "Special 2",
"data": {
"_id": "5d8b1ac3b15bc72d154408e0",
"status": "COMPLETED",
"rating": 4
},
}
]
}
]
}
Try this query
db.testers.aggregate([
{$lookup: {
from: 'demo2',
pipeline: [
{ $sort: {'_id': 1}},
],
as: 'pointValue',
}},
{
$addFields:{
"data":{
$map:{
"input":"$data",
"as":"doc",
"in":{
$mergeObjects:[
"$$doc",
{
"nestedData":{
$map:{
"input":"$$doc.nestedData",
"as":"nestedData",
"in":{
$mergeObjects:[
{ $arrayElemAt: [ {
"$map": {
"input": {
"$filter": {
"input": "$pointValue",
"as": "sn",
"cond": {
"$and": [
{ "$eq": [ "$$sn._id", "$$nestedData._id" ] },
]
}
}
},"as": "data",
"in": {
"name": "$$nestedData.name",
"data":"$$data",
}}
}, 0 ] },'$$nestedData'
],
}
}
}
}
]
}
}
}
}
},
{$project: { pointValue: 0 } }
]).pretty()

Query MongoDB for nested Arrays

Need help for formatting query to find/get values using search parameters with nested Array.
I have an collection as follows
[
{
"_id": "5b3ad55f66479332a0482961",
"timestamp": "2018-06-17T00:30:00.000Z",
"deviceid": "123456",
"values": [
{
"minval": 1,
"minvalues": [
{
"secval": 51,
"secvalues": {
"alt": "300",
"mcc": "404",
"mnc": "46",
"priority": 1
}
},
{
"secval": 52,
"secvalues": {
"alt": "300",
"mcc": "404",
"mnc": "46",
"priority": 1
}
},
{
"secval": 56,
"secvalues": {
"alt": "300",
"mcc": "404",
"mnc": "46",
"priority": 0
}
}
]
}
]
}
]
need the out as follows with search properties as "values.minvalues.secvalues.priority"
[
{
"_id": "5b3ad55f66479332a0482961",
"timestamp": "2018-06-17T00:30:00.000Z",
"deviceid": "123456",
"values": [
{
"minval": 1,
"minvalues": [
{
"secval": 56,
"secvalues": {
"alt": "300",
"mcc": "404",
"mnc": "46",
"priority": 0
}
}
]
}
]
}
]
I tried the following query but with out success
dbRetval.db('ls_gpsdatabase').collection('gpsevent').aggregate([
{ "$match": { "deviceid": { "$in": idList}}},
{ "$sort": { "_id": -1} },
{"$unwind":"$values.minvalues.secvalues"},
//{"$project":{"deviceid":1,"values.minvalues.secvalues.lat":1,"values.minvalues.secvalues.min":1}} ,
{ "$match": { "values.minvalues.secvalues.priority": { "$eq": 1}}},
{ "$group": { "_id": "$deviceid" , "doc": { "$push": "$values.minvalues.secvalues" }}} ]).toArray();
If any can help that would be great full.
You can use $addFields to replace existing field. Since you have two levels of nested arrays you can use $map for outer and $filter for inner to check your condition:
db.col.aggregate([
{
$match: {
"_id": "5b3ad55f66479332a0482961",
"timestamp": "2018-06-17T00:30:00.000Z"
}
},
{
$addFields: {
values: {
$map: {
input: "$values",
as: "value",
in: {
minval: "$$value.minval",
minvalues: {
$filter: {
input: "$$value.minvalues",
as: "minvalue",
cond: {
$eq: [ "$$minvalue.secvalues.priority", 0 ]
}
}
}
}
}
}
}
}
])