I need to find elements which have product.typeCode in ["800", "200", "400"]
{
"_id": "stdcl13#ml.com",
"_class": "com.mongodb.BasicDBObject",
"accounts": [{
"number": "96398-00910620286__DISABILITY",
"product": {
"typeCode": "400",
"nameCode": "401"
},
"dependents": [],
"_id": "stdcl13#ml.com96398-00910620286__DISABILITYDSB"
}, {
"number": "96398-00910620286__LIFECNV",
"product": {
"typeCode": "300",
"nameCode": "LIFECNV"
},
"dependents": [],
"_id": "stdcl13#ss.com"
}]
}
I wrote this query, but its not returning the results
find( {
accounts: {
$elemMatch: {
product: {
typeCode: {
$in: ["400"]
}
}
}
}
})
Please try the below query. You can add the additional values in the IN clause (800, 200, 400).
db.collection.find({ "accounts.product.typeCode" : {
$in: ["400"]
}
}
);
With all three values:-
db.productlist.find({ "accounts.product.typeCode" : {
$in: ["400", "800", "200"]
}
}
);
Related
I'm trying to use aggregate group and match to get my data.
This is my code:
itemShell.aggregate(
[
{
$match: { shell_id_in_whareHouse: {$in:shelfIds}}
},
{
$group: {
_id: "$item",
position:{'$last':'$position'},
total: { $sum: "$amount" }
}
}
],
function(err, results) {
if (err) console.log(err)
else {
res.json(results);
}
}
);
This is how itemShell objects looks like:
{item:1313,position:'2A',amount:500},
{item:1313,position:'2A',amount:200},
{item:1414,position:'1A',amount:500},
{item:1414,position:'2A',amount:800},
{item:1313,position:'1A',amount:300}
My problem is that the outcome of results is: (because of $Last accumulator)
[
{_id:1313,position:'1A',total:1000},
{_id:1414,position:'2A',total:1300},
]
My desired outcome should be:
[
{_id:1313,position:'2A',total:700},
{_id:1414,position:'1A',total:500},
{_id:1414,position:'2A',total:800},
{_id:1313,position:'1A',total:300}
]
So it will group only the objects that item number and position string are the same.
any suggestions ?
You're on the right path, you need to group by two fields using $group stage with _id as an object like below:
ItemShell.aggregate([
{
$match: {}
},
{
$group: {
_id: { item: '$item', position: '$position' },
total: { $sum: '$amount' }
}
},
{
$project: {
_id: 0,
item: '$_id.item',
position: '$_id.position',
total: 1
}
}
]);
Output
[
{
"item": 1313,
"position": "1A",
"total": 300
},
{
"item": 1313,
"position": "2A",
"total": 700
},
{
"item": 1414,
"position": "2A",
"total": 800
},
{
"item": 1414,
"position": "1A",
"total": 500
}
]
Here's a mongo playground: https://mongoplayground.net/p/Ne5h9WkzjEm
I think this should work
itemShell.aggregate([
{
"$group": {
"_id": {
"item": "$item",
"positon": "$positon"
},
"items": {
"$first": "$$ROOT"
},
"amount": {
"$sum": "$amount"
}
}
},
{
"$project": {
"item": "$items.item",
"positon": "$items.position",
"amount": 1,
"_id": "$items._id"
}
}
],
function(err, results) {
if (err) console.log(err)
else {
res.json(results);
}
}
);
You can see the results here : https://mongoplayground.net/p/h7aa_so1Cok
Output:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"amount": 1000,
"item": 1313,
"positon": "2A"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"amount": 1300,
"item": 1414,
"positon": "1A"
}
]
I need to fetch distinct nested documents.
Please find the sample document:
{
"propertyId": 1001820437,
"date": ISODate("2020-07-17T00:00:00.000Z"),
"HList":[
{
"productId": 123,
"name": "Dubai",
"tsh": true
}
],
"PList":[
{
"productId": 123,
"name": "Dubai",
"tsh": false
},
{
"productId": 234,
"name": "India",
"tsh": true
}
],
"CList":[
{
"productId": 234,
"name": "India",
"tsh": false
}
]
}
Expected result is:
{
"produts":[
{
"productId": 123,
"name": "Dubai"
},
{
"productId": 234,
"name": "India"
}
]
}
I tried with this query:
db.property.aggregate([
{
$match: {
"propertyId": 1001820437,
"date": ISODate("2020-07-17T00:00:00.000Z")
}
},
{
"$project": {
"_id": 0,
"unique": {
"$filter": {
"input": {
"$setDifference": [
{
"$concatArrays": [
"$HList.productId",
"$PList.productId",
"$CList.productId"
]
},
[]
]
},
"cond": {
"$ne": [ "$$this", "" ]
}
}
}
}
}
]);
Is $setDifference aggregation is correct choice here?
My query returns only unique product ids but i need a productId with name.
Could someone help me to solve this?
Thanks in advance
You can use $projectfirst to get rid of tsh field and then run $setUnion which ignores duplicated entries:
db.collection.aggregate([
{
$project: {
"HList.tsh": 0,
"PList.tsh": 0,
"CList.tsh": 0,
}
},
{
$project: {
products: {
$setUnion: [ "$HList", "$PList", "$CList" ]
}
}
}
])
Mongo Playground
The following two aggregations return the expected and same result (you can use any of the two):
db.collection.aggregate( [
{
$project: {
_id: 0,
products: {
$reduce: {
input: { $setUnion: [ "$HList", "$PList", "$CList" ] },
initialValue: [],
in: {
$setUnion: [ "$$value", [ { productId: "$$this.productId", name: "$$this.name" } ] ]
}
}
}
}
}
] )
This one is little verbose:
db.collection.aggregate( [
{
$project: { list: { $setUnion: [ "$HList", "$PList", "$CList" ] } }
},
{
$unwind: "$list"
},
{
$group: {
_id: null,
products: { $addToSet: { "productId": "$list.productId", "name": "$list.name" } }
}
},
{
$project: { _id: 0 }
}
] )
db.collection.aggregate([
{
$match: {
"propertyId": 1001820437,
"date": ISODate("2020-07-17T00:00:00.000Z")
}
},
{
$project: {
products: {
$filter: {
input: { "$setUnion" : ["$CList", "$HList", "$PList"] },
as: 'product',
cond: {}
}
}
}
},
{
$project: {
"_id":0,
"products.tsh": 1,
"products.name": 1,
}
},
])
I am struggling to find some examples of using the mongo aggregation framework to process documents which has an array of items where each item also has an array of other obejects (array containing an array)
In the example document below what I would really like is an example that sums the itemValue in the results array of all cases in the document and accross the collection where the result.decision was 'accepted'and group by the document locationCode
However, even an example that found all documents where the result.decision was 'accepted' to show or that summmed the itemValue for the same would help
Many thanks
{
"_id": "333212",
"data": {
"locationCode": "UK-555-5566",
"mode": "retail",
"caseHandler": "A N Other",
"cases": [{
"caseId": "CSE525666",
"items": [{
"id": "333212-CSE525666-1",
"type": "hardware",
"subType": "print cartridge",
"targetDate": "2020-06-15",
"itemDetail": {
"description": "acme print cartridge",
"quantity": 2,
"weight": "1.5"
},
"result": {
"decision": "rejected",
"decisionDate": "2019-02-02"
},
"isPriority": true
},
{
"id": "333212-CSE525666-2",
"type": "Stationery",
"subType": "other",
"targetDate": "2020-06-15",
"itemDetail": {
"description": "staples box",
"quantity": 3,
"weight": "1.66"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-03-03",
"itemValue": "23.01"
},
"isPriority": true
}
]
},
{
"caseId": "CSE885655",
"items": [{
"id": "333212-CSE885655-1",
"type": "marine goods",
"subType": "fish food",
"targetDate": "2020-06-04",
"itemDetail": {
"description": "fish bait",
"quantity": 5,
"weight": "0.65"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-03-02"
},
"isPriority": false
},
{
"id": "333212-CSE885655-4",
"type": "tobacco products",
"subType": "cigarettes",
"deadlineDate": "2020-06-15",
"itemDetail": {
"description": "rolling tobbaco",
"quantity": 42,
"weight": "2.25"
},
"result": {
"decision": "accepted",
"decisionDate": "2020-02-02",
"itemValue": "48.15"
},
"isPriority": true
}
]
}
]
},
"state": "open"
}
You're probably looking for $unwind. It takes an array within a document and creates a separate document for each array member.
{ foos: [1, 2] } -> { foos: 1 }, { foos: 2}
With that you can create a flat document structure and match & group as normal.
db.collection.aggregate([
{
$unwind: "$data.cases"
},
{
$unwind: "$data.cases.items"
},
{
$match: {
"data.cases.items.result.decision": "accepted"
}
},
{
$group: {
_id: "$data.locationCode",
value: {
$sum: {
$toDecimal: "$data.cases.items.result.itemValue"
}
}
}
},
{
$project: {
_id: 0,
locationCode: "$_id",
value: "$value"
}
}
])
https://mongoplayground.net/p/Xr2WfFyPZS3
Alternative solution...
We group by data.locationCode and sum all items with this condition:
cases[*].items[*].result.decision" == "accepted"
db.collection.aggregate([
{
$group: {
_id: "$data.locationCode",
itemValue: {
$sum: {
$reduce: {
input: "$data.cases",
initialValue: 0,
in: {
$sum: {
$concatArrays: [
[ "$$value" ],
{
$map: {
input: {
$filter: {
input: "$$this.items",
as: "f",
cond: {
$eq: [ "$$f.result.decision", "accepted" ]
}
}
},
as: "item",
in: {
$toDouble: {
$ifNull: [ "$$item.result.itemValue", 0 ]
}
}
}
}
]
}
}
}
}
}
}
}
])
MongoPlayground
let's say I have docs such as
{
"nickname": "my nickname",
"comments": [
{
"id": 1
},
{
"id": 1
}
]
}
how do I update it to look like
{
"nickname": "my nickname",
"comments": [
{
"id": 1,
"nickname": "my nickname"
},
{
"id": 1,
"nickname": "my nickname"
}
]
}
This does not seem to be working
db.getCollection('users').update(
{
"comments.nickname": null
},
{ "$set": { "comments.$.nickname": "$nickname" } });
This is just an example to represent my problem.
I would not like to hear about re-structuring and optimizing the fields.
Thanks!
Try this (v4.2):
db.users.updateMany(
{"comments.nickname":null},
[
{"$set": {"comments.nickname": "$nickname"}}
]
)
Note: It will override if any comments.nickname already exists
db.users.aggregate([
{
$match: {
"comments.nickname": null
}
},
{
$addFields: {
comments: {
$map: {
input: "$comments",
in: {
id: "$$this.id",
nickname: {
$cond: [
"$$this.nickname",
"$$this.nickname",
"$nickname"
]
}
}
}
}
}
},
{
$out: "users"
}
])
Note: It will keep already existing values
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 ]
}
}
}
}
}
}
}
}
])