how to use the aggregation of mongodb with meteor - mongodb

i'm using Meteorjs and mongo
I have a collection structure like this:
{
"_id" : "LxMaZhRX7ZbAkiFqF",
"categorie" : "International matches",
"division" : [
{
"nameDivision" : "div 1",
"type" : "Championat"
},
{
"nameDivision" : "div 2",
"type" : "Coupe"
},
{
"nameDivision" : "div 3",
"type" : "Championat"
},
{
"nameDivision" : "div 4",
"type" : "Championat"
}
]
}
I want to have this result in my subscription:
{
"_id" : "LxMaZhRX7ZbAkiFqF",
"categorie" : "International matches",
"division" : [
{
"type" : "Championat",
division:[{
"nameDivision" : "div 1",
"nameDivision" : "div 3",
"nameDivision" : "div 4",
}]
},
{
"type" : "Coupe",
"division":[{
"nameDivision" : "div 2",
}]
},
{
]
}
I need your help on how to use the function with mongodb aggegate to group the Elements
thank you

In Meteor, you can use the meteorhacks:aggregate package to implement the aggregation:
Add to your app with
meteor add meteorhacks:aggregate
Then simply use .aggregate function like below.
var coll = new Mongo.Collection('collectionName');
var pipeline = [
{ "$unwind": "$division" },
{
"$group": {
"_id": "$division.type",
"id": { "$first": "$_id" },
"categorie": { "$first": "$categorie" },
"division": {
"$push": { "nameDivision": "$division.nameDivision" }
}
}
},
{
"$group": {
"_id": "$id",
"categorie": { "$first": "$categorie" },
"division": {
"$push": {
"type": "$_id",
"division": "$division"
}
}
}
}
];
var result = coll.aggregate(pipeline);

Related

How to $lookup in nested array of objects

I have to two collections one is tours and other is destinations so in tours have i have an array of locations which has destination object with an id and that id is belongs to another destinations collection but the thing is i am not be able to lookup details of destination in the array of locations. every tried many query search here too. but not getting expected result.
Tours :
{
"_id" : ObjectId("5f3122f4d8d57e3b9650e5b4"),
"title" : "tour 1",
"locations" : [
{
"destination" : {
"id" : "5ec5ae9037ea99f20a79071a"
},
"services" : {
"hotel" : true
}
},
{
"destination" : {
"id" : "5ec5ae8e37ea99f20a78ef8c"
},
"services" : {
"hotel" : true
}
}
]
}
{
"_id" : ObjectId("5f2d65e68bc6e9155310d147"),
"title" : "tour 2",
"locations" : [
{
"destination" : {
"id" : "5ecf994435c3a6025d5bf126"
},
"services" : {
"hotel" : true
}
}
]
}
{
"_id" : ObjectId("5f2d66398bc6e9155310d161"),
"title" : "tour 3",
"locations" : [
{
"destination" : {
"id" : "5ec5ae8e37ea99f20a78ef8d"
},
"services" : {
"hotel" : true
}
}
]
}
Destinations :
{
"_id" : ObjectId("5ec5ae9037ea99f20a79071a"),
"name" : "dest 1",
"country" : "country name"
}
{
"_id" : ObjectId("5ec5ae8e37ea99f20a78ef8c"),
"name" : "dest 2",
"country" : "country name"
}
{
"_id" : ObjectId("5ec5ae8e37ea99f20a78ef8d"),
"name" : "dest 3",
"country" : "country name"
}
{
"_id" : ObjectId("5ecf994435c3a6025d5bf126"),
"name" : "dest 4",
"country" : "country name"
}
Expected result :
{
"_id" : ObjectId("5f3122f4d8d57e3b9650e5b4"),
"title" : "tour 1",
"locations" : [
{
"destination" : {
"id" : "5ec5ae9037ea99f20a79071a",
"name" : "dest 1",
"country" : "country name"
},
"services" : {
"hotel" : true
}
},
{
"destination" : {
"id" : "5ec5ae8e37ea99f20a78ef8c",
"name" : "dest 2",
"country" : "country name"
},
"services" : {
"hotel" : true
}
}
]
},
{
"_id" : ObjectId("5f2d65e68bc6e9155310d147"),
"title" : "tour 2",
"locations" : [
{
"destination" : {
"id" : "5ecf994435c3a6025d5bf126",
"name" : "dest 4",
"country" : "country name"
},
"services" : {
"hotel" : true
}
}
]
},
{
"_id" : ObjectId("5f2d66398bc6e9155310d161"),
"title" : "tour 3",
"locations" : [
{
"destination" : {
"id" : "5ec5ae8e37ea99f20a78ef8d",
"name" : "dest 3",
"country" : "country name"
},
"services" : {
"hotel" : true
}
}
]
}
Tried query :
db.tours.aggregate([
{
"$addFields": {
"locations": {
"$map": {
"input": "$locations",
"in": {
"$mergeObjects": [
"$$this",
{
"dest_oid": {
"$toObjectId": "$$this.destination.id"
}
}
]
}
}
}
}
},
{ "$unwind": "$locations" },
{ "$lookup": {
"from": "destinations",
"localField": "locations.dest_oid",
"foreignField": "_id",
"as": "locations.dest",
}},
{ "$unwind": "$locations.dest" },
{ "$group": {
"_id": "$_id",
"locations": { "$push": "$locations" }
}}
])
even i have tried this
MongoDB $lookup on nested document
Quick fixes,
$unwind locations array put first because need to convert id to object id
db.tours.aggregate([
{ $unwind: "$locations" },
you skip this part if you have already converted string id t object id
$addFields replace locations.destination.id to object id filtered your logic to short, here no need $map and $mergeObjects options
{
$addFields: {
"locations.destination.id": {
$toObjectId: "$locations.destination.id"
}
}
},
$lookup that you have already did, but change as locations.destination
{
$lookup: {
from: "destinations",
as: "locations.destination",
localField: "locations.destination.id",
foreignField: "_id"
}
},
$unwind locations.destination because its array and we need object
{
$unwind: {
path: "$locations.destination"
}
},
$group that you have already did, few changes, push first destination and services in locations and add first title
{
$group: {
_id: "$_id",
locations: { $push: "$locations" },
title: { $first: "$title" }
}
}
])
Playground: https://mongoplayground.net/p/yaTCij7NRUj
If you can convert/update the string destination.id in the Tours collection to ObjectId if they are not already. Following query should work.
Query:
db.Tours.aggregate([
{
$unwind: "$locations",
},
{
$lookup: {
from: "Destinations",
localField: "locations.destination.id",
foreignField: "_id",
as: "destination",
},
},
{
$project: {
title: "$title",
locations: {
destination: {
$arrayElemAt: ["$destination", 0],
},
services: "$locations.services",
},
},
},
{
$group: {
_id: "$_id",
title: {
$first: "$title",
},
locations: {
$push: "$locations",
},
},
},
]);
Playground Link

how to sort an array in a nested array which is located under an object in mongodb

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"
]
}
}
}

mongodb aggregation with array

I have data like this:
{
"_id" : ObjectId("..."),
"name" : "Entry 1",
"time" : ISODate("2013-12-28T06:00:00.000Z"),
"value" : 100
},
{
"_id" : ObjectId("..."),
"name" : "Entry 2",
"time" : ISODate("2013-12-28T06:00:00.000Z"),
"value" : 200
},
{
"_id" : ObjectId("..."),
"name" : "Entry 1",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 110
},
{
"_id" : ObjectId("..."),
"name" : "Entry 2",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 230
},
{
"_id" : ObjectId("..."),
"name" : "Entry 3",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 25
},
{
"_id" : ObjectId("..."),
"name" : "Entry 4",
"time" : ISODate("2013-12-28T11:00:00.000Z"),
"value" : 15
}
I need the result grouped by time with percentage for each entry like this (group entries by volume "others" when entries for time period more than two, but it's not necessary):
{
"_id": ISODate("2013-12-28T11:00:00.000Z"),
"entries": [
{
"name": "Entry 1",
"percentage": 33.3
},
{
"name": "Entry 2",
"percentage": 66.6
},
]
},
{
"_id": ISODate("2013-12-28T06:00:00.000Z"),
"entries": [
{
"name": "Entry 1",
"percentage": 28.9
},
{
"name": "Entry 2",
"percentage": 60.5
},
{
"name": "Others",
"percentage": 10.5
}
]
}
So the request I was try:
db.collection.aggregate([
{
"$addFields": {
"full_datetime": {"$substr": ["$time", 0, 19]}
}
},
{
"$group": {
"_id": "$full_datetime",
"value_sum": {"$sum": "$value"},
"entries": {
"$push": {
"name": "$name",
"percentage": {
"$multiply": [{
"$divide": ["$value", {"$literal": "$value_sum" }]
}, 100 ]
}
}
}
}
}
])
This request is not work because $value_sum does not exists inside $push.
Please help me how I can to send this $value_sum into the $push statement
You can use one more stage to calculate percentage using $map as,
db.collection.aggregate([
"$addFields": {
"full_datetime": {
"$substr": ["$time", 0, 19]
}
}
}, {
"$group": {
"_id": "$full_datetime",
"value_sum": {
"$sum": "$value"
},
"entries": {
"$push": {
"name": "$name",
"value": "$value"
}
}
}
}, {
"$project": {
"entriesNew": {
"$map": {
"input": "$entries",
"as": "entry",
"in": {
"name": "$$entry.name",
"percentage": {
"$multiply": [{
"$divide": ["$$entry.value", "$value_sum"]
}, 100]
}
}
}
}
}
}])
Output:
/* 1 */
{
"_id" : "2013-12-28T11:00:00",
"entries" : [
{
"name" : "Entry 1",
"percentage" : 28.9473684210526
},
{
"name" : "Entry 2",
"percentage" : 60.5263157894737
},
{
"name" : "Entry 3",
"percentage" : 6.57894736842105
},
{
"name" : "Entry 4",
"percentage" : 3.94736842105263
}
]
}
/* 2 */
{
"_id" : "2013-12-28T06:00:00",
"entries" : [
{
"name" : "Entry 1",
"percentage" : 33.3333333333333
},
{
"name" : "Entry 2",
"percentage" : 66.6666666666667
}
]
}

Issue retrieving subdocuments from MongoDB

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'.

MongoDB: Return objects in a nested array that has the most recent date

I have the following collection:
{
"_id" : ObjectId("56f036e032ea1f27634e2f1f"),
"mockups" : [
{
"versions" : [
{
"title" : "About us 1",
"timestamp" : "2016-01-10T12:31:23.104Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17922")
},
{
"title" : "About us 3",
"timestamp" : "2016-03-11T15:34:11.108Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17923")
},
{
"title" : "About us 2",
"timestamp" : "2016-02-21T16:15:23.101Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17924")
}
],
"_id" : ObjectId("56ec65a9041c87dd6bd17921")
},
{
"versions" : [
{
"title" : "Contact us 1",
"timestamp" : "2016-04-10T11:34:33.103Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17924")
},
{
"title" : "Contact us 3",
"timestamp" : "2016-06-21T16:13:26.101Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17926")
},
{
"title" : "Contact us 2",
"timestamp" : "2016-05-11T13:34:13.106Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17925")
}
],
"_id" : ObjectId("56ec65a9041c87dd6bd17929")
}
]
}
I want to return all mockups with the latest version that would result in something similar to the following:
{
"_id" : ObjectId("56f036e032ea1f27634e2f1f"),
"mockups" : [
{
"versions" : [
{
"title" : "About us 3",
"timestamp" : "2016-03-11T15:34:11.108Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17923")
}
],
"_id" : ObjectId("56ec65a9041c87dd6bd17921")
},
{
"versions" : [
{
"title" : "Contact us 3",
"timestamp" : "2016-06-21T16:13:26.101Z",
"_id" : ObjectId("56ec65a9041c87dd6bd17926")
}
],
"_id" : ObjectId("56ec65a9041c87dd6bd17929")
}
]
}
I have been playing with aggregate, sort, and limit, but I am extremely new to mongodb. I am currently left with having to just return everything and using something like lodash to get the version I need.
Is there a way to query this properly so that I am getting the results I need from the mongo as opposed to using something like lodash after I get the results back?
For a solution using aggregation, would suggest running the following pipeline to get the desired output:
db.collection.aggregate([
{ "$unwind": "$mockups" },
{ "$unwind": "$mockups.versions" },
{ "$sort": { "mockups.versions.timestamp": -1 } },
{
"$group": {
"_id": "$mockups._id",
"title": { "$first": "$mockups.versions.title" },
"timestamp": { "$first": "$mockups.versions.timestamp" },
"id" : { "$first": "$mockups.versions._id" },
"main_id": { "$first": "$_id" }
}
},
{
"$group": {
"_id": "$_id",
"versions": {
"$push": {
"title": "$title",
"timestamp": "$timestamp",
"_id": "$id"
}
},
"main_id": { "$first": "$main_id" }
}
},
{
"$group": {
"_id": "$main_id",
"mockups": {
"$push": {
"versions": "$versions",
"_id": "$_id"
}
}
}
}
])
I didn't actually understood what is the range for "latest" version ,however I think you can use some thing like this:
example:
db.collection.find({
versions.timestamp: {
$gte: ISODate("2010-04-29T00:00:00.000Z"),
$lt: ISODate("2010-05-01T00:00:00.000Z")
}
})
if you want to use the aggregate you can put this condition in the $match .