My collection is in below format,
{
"_id" : ObjectId("5d01fddd3f21c407582e578d"),
"device_name" : "Test Alarm Device",
"description" : "test",
"parameters" : [
{
"parameter_name" : "CO2",
"status" : "on"
},
{
"parameter_name" : "NO",
"status" : "on"
},
{
"parameter_name" : "O2",
"status" : "on"
}
}
Now I wish to overwrite(update) complete object where "parameter_name" : "O2".
For example, in new collection it will look like...
{
"parameter_name" : "O2",
"status" : "on",
"is_active": true,
"min": 5
}
Use $out to replace existing collection, $addFields to overwrite existing array and $map with $cond to update elements based on some criteria. To build a new object based on existing one you can use $mergeObjects, try:
db.collection.aggregate([
{
$addFields: {
parameters: {
$map: {
input: "$parameters",
in: {
$cond: [
{ "$eq": [ "$$this.parameter_name", "O2" ] },
{ $mergeObjects: [ "$$this", { "is_active": true, "min": 5 } ] },
"$$this"
]
}
}
}
}
},
{ $out: "collection" }
])
This will do, but I don't think it is the best solution:
db.collection.updateOne({
_id: ObjectId("5d01fddd3f21c407582e578d"),
{ $set: { "parameters" : [
{
"parameter_name" : "CO2",
"status" : "on"
},
{
"parameter_name" : "NO",
"status" : "on"
},
{
"parameter_name" : "O2",
"status" : "on",
"is_active": true,
"min": 5
}
]
}
}
)
Related
In my 'assemblies' collection, each document contains an embedded array of objects called 'partlist':
{
"_id" : ObjectId("0001"),
"pn" : "01",
"title" : "MyAssembly",
"partlist" : [
{
"id" : "",
"pn" : "1234",
"desc" : "myPart1",
},
{
"id" : "",
"pn" : "5678",
"desc" : "myPart2",
}]
}
Within each object, I need to copy the value from 'partlist.pn' into 'partlist.id'. I used:
db.assemblies.aggregate([{$set:{"partlist.id":"$partlist.pn"}}])
hoping to achieve this:
{
"_id" : ObjectId("0001"),
"pn" : "01",
"title" : "MyAssembly",
"partlist" : [
{
"id" : "1234",
"pn" : "1234",
"desc" : "myPart1",
},
{
"id" : "5678",
"pn" : "5678",
"desc" : "myPart2",
}]
}
Instead it returned to 'id' an array of ALL the 'pn' values in 'partlist':
{
"_id" : ObjectId("0001"),
"pn" : "01",
"title" : "MyAssembly",
"partlist" : [
{
"id" : [
"1234",
"5678"
],
"pn" : "1234",
"desc" : "myPart1",
},
{
"id" : [
"1234",
"5678"
],
"pn" : "5678",
"desc" : "myPart2",
}]
}
What is the correct syntax for copying the one value within each object?
What you can do is, you can use $map to modify each elements and mearg the id with the help of $mergeObject
db.collection.aggregate([
{
$addFields: {
"partlist": {
$map: {
input: "$partlist",
in: {
"$mergeObjects": [
"$$this",
{
id: "$$this.pn"
}
]
}
}
}
}
}
])
Working Mongo playground
If the pn does not exist it retrieves initial object.
db.collection.aggregate([
{
$addFields: {
partlist: {
$map: {
input: "$partlist",
as: "p",
in: {
$cond: [
"$$p.pn",
{
$mergeObjects: [
"$$p",
{
"id": "$$p.pn"
}
]
},
"$$p"
]
}
}
}
}
}
])
Playground
I have a collection data like below.
{
"name": "Devices",
"exten": {
"parameters": [{
"name": "Date",
"value": ["5","2"]
}, {
"name": "Time",
"value": ["2"]
}, {
"name": "Season",
"value": ["6"]
}
]
}
}
I want to take all data which is name "Devices" and sort by first index of "Value" which is parameter name is "Date"
ex: mongo will get
name = "devices"
exten.parameters.name = "Date"
will sort it by
exten.parameters.value[0]
in this example it will be sorted by "5".
below query returns 0 record.
db.brand.aggregate(
{ $match: {
"name" : "Devices"
}},
{ $unwind: "$exten.parameters" },
{ $match: {
'exten.parameters.name': 'Date'
}},
{ $sort: {
'exten.parameters.value': -1
}}
)
The following query can get us the expected output:
db.collection.aggregate([
{
$match:{
"name":"Devices"
}
},
{
$unwind:"$exten.parameters"
},
{
$match:{
"exten.parameters.name":"Date"
}
},
{
$project:{
"name":1,
"exten":1,
"firstParam":{
$arrayElemAt:["$exten.parameters.value",0]
}
}
},
{
$sort:{
"firstParam":1
}
},
{
$project:{
"firstParam":0
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5da02fb86472ba670fd8c159"),
"name" : "Devices",
"exten" : {
"parameters" : [
{
"name" : "Date",
"value" : [
"5",
"2"
]
},
{
"name" : "Date",
"value" : [
"2",
"7"
]
},
{
"name" : "Time",
"value" : [
"2"
]
},
{
"name" : "Season",
"value" : [
"6"
]
}
]
}
}
Output:
{
"_id" : ObjectId("5da02fb86472ba670fd8c159"),
"name" : "Devices",
"exten" : {
"parameters" : {
"name" : "Date",
"value" : [
"2",
"7"
]
}
}
}
{
"_id" : ObjectId("5da02fb86472ba670fd8c159"),
"name" : "Devices",
"exten" : {
"parameters" : {
"name" : "Date",
"value" : [
"5",
"2"
]
}
}
}
I need help to make an aggregation pipeline in mongodb.
The mongodb version i'm using is 4.
The documents stored in database looks like this:
[{
_id : "xxxxxx",
names : [
{ "lang" : "EN", value : "foo" },
{ "lang" : "IT", value : "bar" },
{ "lang" : "NOLANG", value : "baz" }
],
some : "value"
},{
_id : "yyyyyy",
names : [
{ "lang" : "FR", value : "quux" },
{ "lang" : "IT", value : "quuux" },
{ "lang" : "NOLANG", value : "quuuux" }
],
some : "value"
}]
I need to add a field with aggregation that contains the value of a certain language (for this example i'll take "EN"), if no element with requested language is found i need to get the "NOLANG" object value.
So, the result of the aggregation must looks like:
[{
_id : "xxxxxx",
name : "foo",
some : "value"
},{
_id : "yyyyyy",
name : "quuuux",
some : "value"
}]
This is the pipeline i wrote:
[
{
$project : {
names : 0,
name: {
$filter: {
input: '$names',
as: 'name',
cond: {
$switch: {
$branches: [
{
case : {
$eq : ["$$name.lang", "EN"]
},
then : "$$name.value"
} ,{
case : {
$eq : ["$$name.lang", "NOLANG"]
},
then : "$$name.value"
}
],
default : ''
}
}
}
}
}
}
]
It gives me the error: Expected "[" or AggregationStage but "{" found.
What i'm doing wrong? Someone can help me please?
Thanks
You can use below aggregation
db.collection.aggregate([
{ "$project": {
"some": 1,
"name": {
"$arrayElemAt": [
"$names.value",
{
"$cond": [
{
"$ne": [
{ "$indexOfArray": ["$names.lang", "EN"] },
-1
]
},
{ "$indexOfArray": ["$names.lang", "EN"] },
{ "$indexOfArray": ["$names.lang", "NOLANG"] }
]
}
]
}
}}
])
Output
[
{
"_id": "xxxxxx",
"name": "baz",
"some": "value"
},
{
"_id": "yyyyyy",
"name": "quuuux",
"some": "value"
}
]
I have the following dataset:
{
"_id" : ObjectId("59668a22734d1d48cf34de08"),
"name" : "Nobody Cares",
"menus" : [
{
"_id" : "menu_123",
"name" : "Weekend Menu",
"description" : "A menu for the weekend",
"groups" : [
{
"name" : "Spirits",
"has_mixers" : true,
"sizes" : [
"Single",
"Double"
],
"categories" : [
{
"name" : "Vodka",
"description" : "Maybe not necessary?",
"drinks" : [
{
"_id" : "drink_123",
"name" : "Absolut",
"description" : "Fancy ass vodka",
"sizes" : [
{
"_id" : "size_123",
"size" : "Single",
"price" : 300
}
]
}
]
}
]
}
],
"mixers" : [
{
"_id" : "mixer_1",
"name" : "Coca Cola",
"price" : 150
},
{
"_id" : "mixer_2",
"name" : "Lemonade",
"price" : 120
}
]
}
]
}
And I'm attempting to retrieve a single drink from that dataset, I'm using the following aggregate query:
db.getCollection('places').aggregate([
{ $match : {"menus.groups.categories.drinks._id" : "drink_123"} },
{ $unwind: "$menus" },
{ $project: { "_id": 1, "menus": { "groups": { "categories": { "drinks": { "name": 1 } } } } } }
])
However, it's returning the full structure of the dataset along with the correct data.
So instead of:
{
"_id": "drink_123",
"name": "Absolut"
}
I get:
{
"_id": ObjectId("59668a22734d1d48cf34de08"),
"menus": {
"groups": {
"categories": {
"drinks": { "name": "Absolut" }
}
}
}
}
For example. Any ideas how to just retrieve the subdocument?
If you need to retain the deeply nested model then this call will produce the desired output:
db.getCollection('places').aggregate([
{ $match : {"menus.groups.categories.drinks._id" : "drink_123"} },
{ $project: {"_id": '$menus.groups.categories.drinks._id', name: '$menus.groups.categories.drinks.name'}},
{ $unwind: "$name" },
{ $unwind: "$name" },
{ $unwind: "$name" },
{ $unwind: "$name" },
{ $unwind: "$_id" },
{ $unwind: "$_id" },
{ $unwind: "$_id" },
{ $unwind: "$_id" }
])
The numerous unwinds are the result of the deep nesting of the drinks subdocuments.
Though, FWIW, this sort of query does perhaps suggest that the model isn't 'read friendly'.
I want to get which members not present when state change and which member is present.
My given array for state order like:
[{order:1,text:'CS'}, {order:2,text:'IP'}, {order:3,text:'AC'}]
so I want to sort according to this array want to perform some operation with each pare of documents
My documents like:
{
"count" : 2,
"state" : "CS",
"members" : [
{
"email" : "builuu1998#gmail.com",
"date" : ISODate("2016-12-24T03:39:05.720Z")
},
{
"email" : "bactv.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
}
]
},
{
"count" : 1,
"state" : "AC",
"members" : [
{
"email" : "builuu1998#gmail.com",
"date" : ISODate("2016-12-24T03:39:05.720Z")
}
]
},
{
"count" : 3,
"state" : "IP",
"members" : [
{
"email" : "builuu1998#gmail.com",
"date" : ISODate("2016-12-24T03:39:05.720Z")
},
{
"email" : "bactv.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
},
{
"email" : "abc.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
}
]
}
So I want to know which members are not present from one state to another state and which members are present .
In my exam 1st state to 2nd state means (CS - IP): present 2 members and not present 1 member
{
"state": "CS_IP",
"present": [
{
"email" : "builuu1998#gmail.com",
"date" : ISODate("2016-12-24T03:39:05.720Z")
},
{
"email" : "bactv.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
}
],
"notPresent": [
{
"email" : "abc.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
}
]
}
and 2nd state to 3rd state means (IP - AC): present 1 members and not present 2 member
{"state": "IP_AC",
"present": [
{
"email" : "builuu1998#gmail.com",
"date" : ISODate("2016-12-24T03:39:05.720Z")
}
],
"notPresent": [
{
"email" : "bactv.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
},
{
"email" : "abc.hn#gmail.com",
"date" : ISODate("2016-12-25T02:32:48.698Z")
}
]}
How can I achieve this using aggregate query because I need some aggregate operation after this stage complete
You can perform one aggregation request per "couple" of state like this for ["IP", "AC"] :
db.exams.aggregate([{
$match: {
"state": {
$in: ["IP", "AC"]
}
}
}, {
"$group": {
"_id": 1,
"group1": { "$first": "$members" },
"group2": { "$last": "$members" }
}
}, {
"$project": {
"present": { "$setIntersection": ["$group1", "$group2"] },
"notPresent": {
$setUnion: [
{ "$setDifference": ["$group1", "$group2"] },
{ "$setDifference": ["$group2", "$group1"] }
]
}
}
}])
Note that this will only work for 2 elements to match (here ["IP", "AC"]) since we have to create two new fields group1 & group2 to $setIntersection and $setDifference (as there is no $group with $setIntersection and $setDifference)
The query above will give :
{
"_id": 1,
"present": [
{ "email": "builuu1998#gmail.com", "date": ISODate("2016-12-24T03:39:05.720Z") }
],
"notPresent": [
{ "email": "abc.hn#gmail.com", "date": ISODate("2016-12-25T02:32:48.698Z") },
{ "email": "bactv.hn#gmail.com", "date": ISODate("2016-12-25T02:32:48.698Z") }
]
}