I am new to MongoDB.
my collections are authors and books. its many to many associations
my authors collections
[{
"id": "11",
"name": "Sam",
"age": 40
},
{
"id": "12",
"name": "Jack",
"age": 20
},
{
"id": "22",
"name": "Smith",
"age": 35
}]
my books collections
[{
"id": "123",
"title": "Hello World",
"price": 200,
"authors":["Sam","Jack"]
},
{
"id": "34",
"title": "Good Day",
"price": 100,
"authors":["Smith"]
}]
This is my postman result.
[{
"authors": [
{
"id": "11",
"name": "Sam",
"age": 40,
},
{
"id": "12",
"name": "Jack",
"age": 20,
}
],
"id": "123",
"title": "Hello World",
"price": 200,
}]
I put query in mongo shell to find books but result only shown book details not shown authors(child entries).
how to I get books with authors entries in mongo shell command(like postman result).
Thanks.
Try the following code:
<db>.books.aggregate([
{
'$project': {
'id': 1,
'title': 1,
'price': 1,
'authors': 1,
'numberOfAuthors': {
'$cond': {
'if': {
'$isArray': '$authors'
},
'then': {
'$size': '$authors'
},
'else': 0
}
}
}
}, {
'$match': {
'numberOfAuthors': {
'$eq': 2
}
}
}, {
'$lookup': {
'from': 'authors',
'localField': 'authors',
'foreignField': 'name',
'as': 'authors'
}
}
])
Used projection followed by match before lookup.
Related
I have a collection where from the backend user can input multiple same name bikes but with different registration number but in front-End I want them to be grouped by matching the same name but as user updates separately display image changes but I want only one display image as it is 1 vehicle
provided there is a node created I will implement it we can sort it by the latest and take the price and image of it
Activa -2 Count
KTM -1 Count
but there is a catch.
Activa 2 bikes but I want only count 2 and the price as it is the same in an array I want only 1 and the same applies to displayimage here display image file path is different but I want the latest one only Sharing data below
Data:
[
{
"price": [
{
"Description": "Hourly",
"Price": "1"
},
{
"Description": "Daily",
"Price": "11"
},
{
"Description": "Monthly",
"Price": "111"
}
],
"_id": "62e69ee3edfe4d0f3cb4994a",
"bikename": "KTM",
"bikenumber": "KA05HM2034",
"bikebrand": {
"id": 1,
"label": "Honda"
},
"freekm": 234,
"displayimage": {
"file": "bike-2020-honda-city-exterior-8-1659281111883.jpg",
"file_path": "https://www.example.com/images/upload/bike-2020-honda-city-exterior-8-1659281111883.jpg",
"idx": 1
}
},
{
"price": [
{
"Description": "Hourly",
"Price": "1"
},
{
"Description": "Daily",
"Price": "11"
},
{
"Description": "Monthly",
"Price": "111"
}
],
"_id": "62dba8418ef8f51f454ed757",
"bikename": "Activa",
"bikenumber": "KA05HM2033",
"bikebrand": {
"id": 1,
"label": "Honda"
},
"freekm": 234,
"displayimage": {
"file": "bike-v_activa-i-deluxe-1658562557459.jpg",
"file_path": "https://www.example.com/images/upload/bike-v_activa-i-deluxe-1658562557459.jpg",
"idx": 0
}
},
{
"price": [
{
"Description": "Hourly",
"Price": "1"
},
{
"Description": "Daily",
"Price": "11"
},
{
"Description": "Monthly",
"Price": "111"
}
],
"_id": "62d7ff7e70b9ab38c6ab0cb1",
"bikename": "Activa",
"bikenumber": "KA05HM2223",
"bikebrand": {
"id": 1,
"label": "Honda"
},
"freekm": 234,
"afterfreekmprice": 22,
"descreption": "Activa",
"displayimage": {
"file": "bike-v_activa-i-deluxe-1658322798414.jpg",
"file_path": "https://www.example.com/images/upload/bike-v_activa-i-deluxe-1658322798414.jpg",
"idx": 0
}
}
]
Expected:
[
{
"_id":{
"price": [
{
"Description": "Hourly",
"Price": "1"
},
{
"Description": "Daily",
"Price": "11"
},
{
"Description": "Monthly",
"Price": "111"
}
],
"_id": "62dba8418ef8f51f454ed757",
"bikename": "Activa",
"bikebrand": {
"id": 1,
"label": "Honda"
},
"freekm": 234,
"displayimage": {
"file": "bike-v_activa-i-deluxe-1658562557459.jpg",
"file_path": "https://www.example.com/images/upload/bike-v_activa-i-deluxe-1658562557459.jpg",
"idx": 0
}
},
"count": 2
},
{
"_id":{
"price": [
{
"Description": "Hourly",
"Price": "1"
},
{
"Description": "Daily",
"Price": "11"
},
{
"Description": "Monthly",
"Price": "111"
}
],
"_id": "62e69ee3edfe4d0f3cb4994a",
"bikename": "KTM",
"bikebrand": {
"id": 1,
"label": "Honda"
},
"freekm": 234,
"displayimage": {
"file": "bike-2020-honda-city-exterior-8-1659281111883.jpg",
"file_path": "https://www.example.com/images/upload/bike-2020-honda-city-exterior-8-1659281111883.jpg",
"idx": 1
}
}
"count": 1
}
]
You can use the aggregation pipeline,
$sort by _id in descending order
$group by bikename and get the first root document that is latest one in root and count total documents in count
$project to show required documents
db.collection.aggregate([
{ $sort: { _id: -1 } },
{
$group: {
_id: "$bikename",
root: { $first: "$$ROOT" },
count: { $sum: 1 }
}
},
{
$project: {
_id: "$root",
count: 1
}
}
])
Playground
You can use $group for this:
db.collection.aggregate([
{$group: {
_id: "$bikename",
count: {$sum: 1},
data: {$first: "$$ROOT"}
}
},
{$set: {"data.count": "$count"}},
{$replaceRoot: {newRoot: "$data"}}
])
See how it works on the playground example
I have a MongoDB schema that looks like this
const ProductModel = new Schema({
subcategory: {
type : mongoose.Schema.Types.ObjectId,
ref : "Subcategory",
},
product_name: {
type: String
},
description: {
type: String
},
price: {
type: Number
},
});
And a subcategory schema:
const SubcategoryModel = new Schema({
subcategoryName: {
type: String,
}
});
The input query before aggregation looks like this:
[
{
"_id": "111",
"subcategory": {
"_id": "456",
"categoryName": "Sneakers",
},
"product_name": "Modern sneaker",
"description": "Stylish",
"price": 4400
},
{
"_id": "222",
"subcategory": {
"_id": "456",
"categoryName": "Sneakers",
},
"product_name": "Blue shoes",
"description": "Vived colors",
"price": 7500
},
{
"_id": "333",
"subcategory": {
"_id": "123",
"categoryName": "Jackets",
"__v": 0
},
"product_name": "Modern jacket",
"description": "Stylish",
"price": 4400
},
}
]
The final result of the query should look like this:
{
"Sneakers":[
{
"product_name":"Modern sneaker",
"description":"Stylish",
"price":"4400"
},
{
"product_name":"Blue shoes",
"description":"Vived colors",
"price":"7500"
},
"Jackets":{
"...."
}
]
}
Subcategory before aggregation:
"subcategories": [
{
"_id": "123",
"categoryName": "Jackets",
},
{
"_id": "456",
"categoryName": "Sneakers",
}
]
I'm trying to populate the subcategory, And then group the products by their subcategoryName field.
You can use this aggregation query:
First $lookup to do the join between Product and Subcategory creating the array subcategories.
Then deconstructs the array using $unwind.
$group by the name of subproduct adding the entire object using $$ROOT.
The passes the fields you want using $project.
And replaceRoot to get key value into arrays as Sneakers and Jackets.
db.Product.aggregate([
{
"$lookup": {
"from": "Subcategory",
"localField": "subcategory.categoryName",
"foreignField": "categoryName",
"as": "subcategories"
}
},
{
"$unwind": "$subcategories"
},
{
"$group": {
"_id": "$subcategories.categoryName",
"data": {
"$push": "$$ROOT"
}
}
},
{
"$project": {
"data": {
"product_name": 1,
"description": 1,
"price": 1
}
}
},
{
"$replaceRoot": {
"newRoot": {
"$arrayToObject": [
[
{
"k": "$_id",
"v": "$data"
}
]
]
}
}
}
])
Example here
With your provided data, result is:
[
{
"Sneakers": [
{
"description": "Stylish",
"price": 4400,
"product_name": "Modern sneaker"
},
{
"description": "Vived colors",
"price": 7500,
"product_name": "Blue shoes"
}
]
},
{
"Jackets": [
{
"description": "Stylish",
"price": 4400,
"product_name": "Modern jacket"
}
]
}
]
I have the collection data from a csv file with header. When i run my query
db.ties.aggregate(
[
{
$group:
{
_id: { "SHOP": "$SHOP" },
isLinkedTo: { $push: { "PERSON": "$PERSON", "CITY": "$CITY", "ROOM": "$ROOM", "STYLE": "$STYLE", "hasDonated": {"DATE": "$DATE", "OBJECT": "$OBJECT", "COST": "$COST", "COLOR": "$COLOR", "PAYMENT": "$PAYMENT"}}}
}
},
{ $out: "ties"}
],
{ allowDiskUse: true }
)
I have like result:
{
"_id": {
"Shop": "FirstShopNameCovered"
},
"isLinkedTo": [{
"PERSON": "Carleen",
"CITY": "Rome",
"ROOM": "Kitchen",
"STYLEPREFERED": "Modern",
"hasDonated": {
"DATE": "2019-10-11",
"OBJECT": "Set of dishes",
"COST": 72,
"COLOR": "White",
"PAYMENT": "Credit card"
}
}, {
"PERSON": "Carleen",
"CITY": "Rome",
"ROOM": "Kitcher",
"STYLEPREFERED": "Modern",
"hasDonated": {
"DATE": "2018-10-26",
"OBJECT": "Set of chairs",
"COST": 353,
"COLOR": "Grey",
"PAYMENT": "Coupon"
}
}, {
"PERSON": "Pernick",
"CITY": "Venezia",
"ROOM": "Bathroom",
"STYLE": "Minimalist",
"hasDonated": {
"DATE": "2018-09-18",
"OBJECT": "Mirror",
"COST": 68,
"COLOR": "Brown",
"PAYMENT": "Credit card"
}
}
You can see that there is replicated the Person "PERSON": "Carleen" with all data with 2 different arrays hasDonated.
I wish have something like this result, with person not replicated that contains all hasDonated arrays where he is present:
"_id": {
"Shop": "NameCovered"
},
"isLinkedTo": [{
"PERSON": "Carleen",
"CITY": "Rome",
"ROOM": "Kitchen",
"STYLE": "RetrĂ²",
"hasDonated": {
"DATE": "2019-10-11",
"OBJECT": "Set of dishes",
"COST": 72,
"COLOR": "White",
"PAYMENT": "Credit card"
},
{
"DATE": "2018-10-26",
"OBJECT": "Chair",
"COST": 53,
"COLOR": "Grey",
"PAYMENT": "Coupon"
}
}, {
"PERSON": "Pernick",
"CITY": "Venezia",
"ROOM": "Bathroom",
"STYLE": "Minimalist",
"hasDonated": {
"DATE": "2018-09-18",
"OBJECT": "Mirror",
"COST": 68,
"COLOR": "Brown",
"PAYMENT": "Credit card"
}
How can I do to have the result like this?
First we need to $unwind to flat the array. Then group the hasDonated using $group where unique is found by combination of "_id" and "PERSON" as you mentioned.
[
{
"$unwind": "$isLinkedTo"
},
{
$group: {
_id: {
_id: "$_id",
per: "$isLinkedTo.PERSON"
},
isLinkedTo: {
$first: {
PERSON: "$isLinkedTo.PERSON",
CITY: "$isLinkedTo.CITY",
ROOM: "$isLinkedTo.ROOM",
STYLEPREFERED: "$isLinkedTo.STYLEPREFERED"
}
},
hasDonated: {
$addToSet: "$isLinkedTo.hasDonated"
}
}
},
{
$addFields: {
_id: "$_id._id",
"isLinkedTo.hasDonated": "$hasDonated"
}
},
{
$project: {
hasDonated: 0
}
},
{
$group: {
_id: "$_id",
isLinkedTo: {
$push: "$isLinkedTo"
}
}
}
]
Working Mongo playground
I need to aggregate for each "Product" object from the sales database, and sum "Price" and "Quantity" to make a product classification.
I was able to group by "Products" but I can't sum Price and Quantity to the each object.
{$group: {
_id: '$products.items',
totalprice:{$sum: "$products.items.price"},
}}
Below sample of sales database, where I need to return the sum of the "Price" and "Quantity" fields sold for each "Products".
{
"_id": {
"$oid": "5d753707c0cd851e80da914c"
},
"created_on": {
"$date": {
"$numberLong": "1567962886000"
}
},
"custumer": {
"name": "Teste",
"cep": "teste",
"address": "teste",
"district": "test",
"city": "test",
"numb": "50",
"comple": "test",
"state": "test",
"cpf": "test",
"birth": "30/09/1977",
"email": "test#gmail.com",
"phone": {
"$numberDouble": "1111111111111"
},
"gender": "M",
"portalt": {
"status": "true",
"vendor": "test",
"phone": {
"$numberDouble": "11111111111"
},
"sim": "011111111111",
"salesnumb": "1222222222222222222"
}
},
"payment": {
"method": "Boleto",
"type": "Parcelado",
"installments": "5",
"billing_date": "15"
},
**"products": {
"items": {
"5d515979736802000415a561": {
"item": {
"_id": "5d515979736802000415a561",
"name_produto": "Product 1",
"resumo": "Minutos ilimitados,20GB + 2GB",
"price": "110",
"_image": "images/test.jpg"
},
"quantity": {
"$numberInt": "2"
},
"price": {
"$numberInt": "220"
}
},
"5d515aba736802000415a562": {
"item": {
"_id": "5d515aba736802000415a562",
"name_produto": "Product 2",
"resumo": "Minutos ilimitados,3GB + 1GB",
"price": "80",
"_image": "images/test.jpg"
},
"quantity": {
"$numberInt": "1"
},
"price": {
"$numberInt": "80"
}
},
"5d515dbf736802000415a564": {
"item": {
"_id": "5d515dbf736802000415a564",
"name_produto": "Product 3",
"resumo": "Minutos ilimitados,30GB + 3GB",
"price": "150",
"_image": "images/test.jpg"
},
"quantity": {
"$numberInt": "1"
},
"price": {
"$numberInt": "150"
}
}
},**
"totalItems": {
"$numberInt": "4"
},
"totalPrice": {
"$numberInt": "450"
}
},
"seller": {
"_id": {
"$oid": "5cd086787dc59921bcad94d8"
},
"name": "test"
}
}
I need output something like:
_id:Object
5d515979736802000415a561:{sum_price: 300, sum_quantity: 30 }
5d515aba736802000415a562:{sum_price: 500, sum_quantity: 60 }
5d515dbf736802000415a564:{sum_price: 600, sum_quantity: 70 }
Thanks so much!
So let's go with the OP ask to sum the individual product price and quantity. Stripping away the other fields which are not relevant to the ask, we arrive at something like this:
var r =
[
{
_id:0,
"products": {
"items": {
"5d515979736802000415a561": {
"quantity": 2,
"price": 220,
},
"5d515aba736802000415a562": {
"quantity": 1,
"price": 80
}
}
}
}
, {
_id:1,
"products": {
"items": {
"5d515979736802000415a561": { // deliberately same id as doc above but different quantity and price
"quantity": 3,
"price": 330
},
"5d515aba736802000415a562": { // same
"quantity": 2,
"price": 160
},
"5d515979736802000415ZZZZ": { // different than above; adds "third item"
"quantity": 4,
"price": 200
}
}
}
}
];
Note that the whole inner item field is basically not important, not the least of which it only contains the unit price, not the total price (amount) and quantity per product.
"5d515dbf736802000415a564": {
"item": {
"_id": "5d515dbf736802000415a564",
// etc
So now we employ the $objectToArray to turn the keys into rvals. That gives us something we can $group on, and so here is a solution:
db.foo.aggregate([
{$project: {X: {$objectToArray: "$products.items"}}}
,{$unwind: "$X"}
,{$group: {_id: "$X.k", tot_q: {$sum:"$X.v.quantity"}, tot_amt: {$sum:"$X.v.price"}} }
]);
which given the input above yields:
{ "_id" : "5d515979736802000415ZZZZ", "tot_q" : 4, "tot_amt" : 200 }
{ "_id" : "5d515aba736802000415a562", "tot_q" : 3, "tot_amt" : 240 }
{ "_id" : "5d515979736802000415a561", "tot_q" : 5, "tot_amt" : 550 }
I have my json object like this
{
"_id": "5c2e811154855c0012308f00",
"__pclass": "QXRzXFByb2plY3RcTW9kZWxcUHJvamVjdA==",
"id": 44328,
"name": "Test project via postman2//2",
"address": "some random address",
"area": null,
"bidDate": null,
"building": {
"name": "Health Care Facilities",
"type": "Dental Clinic"
},
"collaborators": [],
"createdBy": {
"user": {
"id": 7662036,
"name": "Someone Here"
},
"firm": {
"id": 2520967,
"type": "ATS"
}
},
"createdDate": "2019-01-03T21:39:29Z",
"customers": [],
"doneBy": null,
"file": null,
"firm": {
"id": 1,
"name": "MyFirm"
},
"leadSource": {
"name": "dontknow",
"number": "93794497"
},
"location": {
"id": null,
"city": {
"id": 567,
"name": "Bahamas"
},
"country": {
"id": 38,
"name": "Canada"
},
"province": {
"id": 7,
"name": "British Columbia"
}
},
"modifiedBy": null,
"modifiedDate": null,
"projectPhase": {
"id": 1,
"name": "pre-design"
},
"quotes": [{
"id": 19,
"opportunityValues": {
"Key1": 100,
"Key2 Key2": 100,
"Key3 Key3 Key3": 200,
}
}],
"specForecast": [],
"specIds": [],
"tags": [],
"valuation": "something"
}
I am trying to aggregate using this query in MongoDB. My aggregation key is 4 level deep and also contains spaces. On all online examples shows me the aggregation at the first level. Looking to the online codes, I tried to re-iterate the same with my 4th level deep key.
db.mydata.aggregate([
{$match: {"id": 44328 } } ,
{$group: { _id: "$quotes.id",
totalKey2:{ $sum: "$quotes.opportunityValues.Key2 Key2"},
totalKey3:{ $sum: "$quotes.opportunityValues.Key3 Key3 Key3"}
}
}
]);
This should return
_id totalKey2 totalKey3
0 19 100 300
But it is returning
_id totalKey2 totalKey3
0 19 0 0
What am I doing Wrong?
Although it's not recommended to use space in field names in Mongo, it works as expected.
The problem with your query is that "quotes" is an array and you should first unwind it before grouping it.
This works as expected:
db.mydata.aggregate([
{ $match: { "id": 44328 } } ,
{ $unwind: "$quotes" },
{ $group: { _id: "$quotes.id",
totalKey2:{ $sum: "$quotes.opportunityValues.Key2 Key2" },
totalKey3:{ $sum: "$quotes.opportunityValues.Key3 Key3 Key3" } }
}
]);