mongodb - $sum returns 0 - mongodb

The aim of this query is when you are "Given an employee return a total sales number".
My first query was this
db.Employee.aggregate([{$lookup: {from: "Invoice", localField: "_id", foreignField: "_id", as: "Invoices"}}, {$match: {_id: 2}}]).pretty()
which returned the below snippet though it only returns one customer even though the employee has several customers. I'm not totally sure why it returns just one.
{
"_id" : 2,
"LastName" : "Edwards",
"FirstName" : "Nancy",
"Title" : "Sales Manager",
"ReportsTo" : 1,
"BirthDate" : ISODate("1958-12-08T00:00:00Z"),
"HireDate" : ISODate("2002-05-01T00:00:00Z"),
"Address" : "825 8 Ave SW",
"City" : "Calgary",
"State" : "AB",
"Country" : "Canada",
"PostalCode" : "T2P 2T3",
"Phone" : "+1 (403) 262-3443",
"Fax" : "+1 (403) 262-3322",
"Email" : "nancy#chinookcorp.com",
"Invoices" : [
{
"_id" : 2,
"CustomerId" : 4,
"InvoiceDate" : ISODate("2009-01-02T00:00:00Z"),
"BillingAddress" : "Ullevålsveien 14",
"BillingCity" : "Oslo",
"BillingState" : null,
"BillingCountry" : "Norway",
"BillingPostalCode" : "0171",
"Total" : 3.96,
"InvoiceLines" : [
{
"_id" : 3,
"TrackId" : 6,
"UnitPrice" : 0.99,
"Quantity" : 1
},
{
"_id" : 4,
"TrackId" : 8,
"UnitPrice" : 0.99,
"Quantity" : 1
},
{
"_id" : 5,
"TrackId" : 10,
"UnitPrice" : 0.99,
"Quantity" : 1
},
{
"_id" : 6,
"TrackId" : 12,
"UnitPrice" : 0.99,
"Quantity" : 1
}
]
}
]
}
In an attempt to get around this and achieve my aim of returning the total sales number I created this new query
db.Employee.aggregate([{$unwind: "$_id"}, {$lookup: {from: "Invoice", localField: "_id", foreignField: "_id", as: "Invoices"}}, {$match: {_id: 2}}, {$group: {_id: "$_id", Total: {$sum: "$Total"}}}]).pretty()
though it just returns { "_id" : 2, "Total" : 0 }
Having looked at other issues I'm thinking it might be because the documents are nested though having tried the potential solution it has yielded no output. No errors which is good but nothing happens. Here is the query I tried:
db.Employee.aggregate([{$unwind: "$_id"}, {$unwind: "$_id.Invoices"}, {$unwind: "$_id.Invoices.InvoiceLines"}, {$lookup: {from: "Invoice", localField: "_id", foreignField: "_id", as: "Invoices"}}, {$match: {_id: 2}}, {$group: {_id: "$_id", Total: {$sum: "$Total"}}}]).pretty()
I don't understand why this query is not returning the total. Everything I've tried has failed. Any help is appreciated.
Edit:
My database is structured as so: Employee>Customer>Invoice. Customer references Employee via SupportRepId which is the same as an employee id as each customer is assigned an employee and Invoice contains the customer id as each invoice has a customer. So I want to get all invoices and sum there total based on an employee id.
Employee Example:
{
"_id":3,
"LastName":"Peacock",
"FirstName":"Jane",
"Title":"Sales Support Agent",
"ReportsTo":2,
"BirthDate": ISODate("1973-08-29T00:00:00 Z"),
"HireDate": ISODate("2002-04-01T00:00:00 Z"),
"Address":"1111 6 Ave SW",
"City":"Calgary",
"State":"AB",
"Country":"Canada",
"PostalCode":"T2P 5M5",
"Phone":"+1 (403) 262-3443",
"Fax":"+1 (403) 262-6712",
"Email":"jane#chinookcorp.com"
}
Customer Example:
{
"_id":1,
"FirstName":"Luís",
"LastName":"Gonçalves",
"Company":"Embraer - Empresa Brasileira de Aeronáutica S.A.",
"Address":"Av. Brigadeiro Faria Lima, 2170",
"City":"São José dos Campos",
"State":"SP",
"Country":"Brazil",
"PostalCode":"12227-000",
"Phone":"+55 (12) 3923-5555",
"Fax":"+55 (12) 3923-5566",
"Email":"luisg#embraer.com.br",
"SupportRepId":3
}
Invoice Example:
{
"_id":2,
"CustomerId":4,
"InvoiceDate": ISODate("2009-01-02T00:00:00 Z"),
"BillingAddress":"Ullevålsveien 14",
"BillingCity":"Oslo",
"BillingState":null,
"BillingCountry":"Norway",
"BillingPostalCode":"0171",
"Total":3.96,
"InvoiceLines":[
{
"_id":3,
"TrackId":6,
"UnitPrice":0.99,
"Quantity":1
},
{
"_id":4,
"TrackId":8,
"UnitPrice":0.99,
"Quantity":1
},
{
"_id":5,
"TrackId":10,
"UnitPrice":0.99,
"Quantity":1
},
{
"_id":6,
"TrackId":12,
"UnitPrice":0.99,
"Quantity":1
}
]
}

See if this works
db.Employee.aggregate([
{
$match: {
"Employee._id": 2
}
},
{
$lookup: {
from: "Customer",
localField: "_id",
foreignField: "customer.SupportRepId",
as: "customer"
}
},
{
$lookup: {
from: "Invoice",
localField: "customer._id",
foreignField: "invoice.CustomerId",
as: "invoice"
}
}
])

Related

Aggregate Query returns null array

I have three collections in EmployeeDB.
Employee
{
"user_id" : "EMP001",
"FirstName" : "Manoj",
"LastName" : "sharma",
"Status" : "0/1",
"CreateDate" : "1988-10-11T18:30:00.000Z"
}
EmpContact
{
"user_id" : "EMP001",
"Phone" : "9999999999",
"Email" : "xyz#gmail.com"
}
EmpInfo
{
"user_id" : "EMP001",
"Gender" : "Male",
"Age" : NumberInt(20),
"Designation" : "manager",
"Salary" : "5000"
}
I need to group the three collections and display all fields.
I tried the below code,
db.Employee.aggregate([
{$lookup: {from: "EmpContact",localField: "user_id",foreignField: "user_id",as: "contact"}},
{$unwind:"$EmpContact"},
{$lookup: {from: "EmpInfo",localField: "user_id",foreignField: "user_id",as: "empinfo"}},
{$unwind:"$EmpInfo"},
{
$match:{user_id : "EMP001"}
}
]).toArray();
But I got an empty array, Please help me...
The problem comes from your $unwind.
Since you name your field as contact in the $lookup, the field EmpContact doesn't exist.
The same thing for the second unwind, EmpInfo doesn't exist but empinfo does
Here is the full query
db.Employee.aggregate([
{
$lookup: {
from: "EmpContact",
localField: "user_id",
foreignField: "user_id",
as: "contact"
}
},
{
$unwind: "$contact"
},
{
$lookup: {
from: "EmpContact",
localField: "user_id",
foreignField: "user_id",
as: "empinfo"
}
},
{
$unwind: "$empinfo"
},
{
$match: {
user_id: "EMP001"
}
}
])
Try it here

MongoDB Aggregation - How can I" $lookup" a nested document "_id"?

I successfully thanks to the help of the people here managed to $lookup two IDs in my document with their representive document in another collection. The next step I need to take is to further lookup a "nested" ID (refering to a document in another collection).
I tried to simply put another $lookup pipeline up but that just worked part-wise.
So it happens that an "empty" document was included into the chieftain attributes and all other attributes of chieftain where somewhat removed.
See my current aggregate:
db.getCollection('village').aggregate([
{
"$match": { _id: "111" }
},
{
"$lookup": {
from: "character",
localField: "chieftainId",
foreignField: "_id",
as: "chieftain"
}
},
{
"$lookup": {
from: "character",
localField: "villagerIds",
foreignField: "_id",
as: "villagers"
}
},
{
"$lookup": {
from: "bloodline",
localField: "chieftain.bloodline",
foreignField: "_id",
as: "chieftain.bloodline"
}
},
{ "$project" : { "villagerIds" : 0, "chieftainId" : 0}},
{ "$unwind" : "$chieftain" }
])
The result of that is the following:
{
"_id" : "111",
"name" : "MyVillage",
"reputation" : 0,
"chieftain" : {
"bloodline" : []
},
"villagers" : [
{
"_id" : "333",
"name" : "Bortan",
"age" : 21,
"bloodlineId" : "7f02191f-90af-406e-87ff-41d5b4387999",
"villageId" : "foovillage",
"professionId" : "02cbb10a-6c0f-4249-a932-3f40e12d32c5"
},
{
"_id" : "444",
"name" : "Blendi",
"age" : 21,
"bloodlineId" : "b3a8ffeb-27aa-4e2e-a8e6-b382554f326a",
"villageId" : "foovillage",
"professionId" : "45dc9350-c84a-491d-a49a-524834dd5773"
}
]
}
I expected the chieftain part to look like this (this is how the chieftain document looks like without the 'last' $lookup I added):
"chieftain" : {
"_id" : "222",
"name" : "Bolzan",
"age" : 21,
"bloodlineId" : "7c2926f9-2f20-4ccf-846a-c9966970fa9b", // this should be resolved/lookedup
"villageId" : "foovillage",
},
At the point of the lookup, chieftan is an array, so setting the chieftan.bloodline replaces the array with an object containing only the bloodline field.
Move the { "$unwind" : "$chieftain" } stage to before the bloodline lookup stage so the lookup is dealing with an object.

How to join two collections based on the _id field in mongodb

I have two collections called orders and items as shown below. Now, I'm trying to join these collections based on the _id field. Can we use "$lookup" operator for this scenario? Or is there any other method to resolve this problem.
db.orders.insert([
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 }
])
db.items.insert([
{ "_id" : 1, "item" : "almonds", description: "almond clusters", "instock" : 120 },
{ "_id" : 2, "item" : "bread", description: "raisin and nut bread", "instock" : 80 },
{ "_id" : 3, "item" : "pecans", description: "candied pecans", "instock" : 60 }
])
Can anyone please help me out regarding this issue ...
Try following code:
db.orders.aggregate([
{
$lookup:
{
from: "items",
localField: "_id",
foreignField: "_id",
as: "item"
}
},
{ $unwind: "$item" },
{
$project: {
"_id": 1,
"price": 1,
"quantity": 1,
"description": "$item.description",
"instock": "$item.instock"
}
}
])
Since you know that there will be 1 to 1 relationship you can unwind $lookup results to have just one embedded item for each order. Then you can project your results to get flat structure of JSON. This will give you results in following shape:
{
"_id" : 1,
"price" : 12,
"quantity" : 2,
"description" : "almond clusters",
"instock" : 120
}
Try This.
db.orders.aggregate([
{ $lookup:
{
from: 'items',
localField: '_id',
foreignField: '_id',
as: 'get_data'
}
}
]).exec(function(err, res) {
if (err) throw err;
console.log(res);
});

MongoDB - rejecting records with $lookup on a value from the $lookup record

I want to get all invoices based on duedates - AND based on the status from the booking table.
I want invoices where booking.status < 5
I do NOT want invoices where booking.status >= 5
This is my aggregate:
db.getCollection('invoice').aggregate([
{
$match: {
dueDate: {$gte: 1483596800},
dueDate: {$lte: 1583596800}
}
},
{
$lookup: {
from: "booking",
localField: "bookingId",
foreignField: "_id",
as: "booking"
}
}
])
And here are the tables....
table invoice
{
"_id" : "IKUU",
"bookingId" : "AAAAA",
"dueDate" : 1489470468,
"invoiceLines" : [
{
"lineText" : "Rent Price",
"amountPcs" : "7 x 2071",
"amountTotal" : 14497
},
{
"lineText" : "Discount",
"amountPcs" : "",
"amountTotal" : -347
}
]
}
{
"_id" : "1NYRO",
"bookingId" : "BBBBB",
"dueDate" : 1489471351,
"invoiceLines" : [
{
"lineText" : "Reservation / Booking fee",
"amountPcs" : "1 x 2000",
"amountTotal" : 2000
}
]
}
table booking
{
"_id" : "AAAAA",
"checkin" : 1449756800,
"price" : 5000,
"status" : 1
}
{
"_id" : "BBBBB",
"checkin" : 1449756800,
"price" : 6000,
"status" : 5
}
I tried putting some $match{booking.status: {$lt: 5}} but I cant get it to work.
The result should be the invoice with "bookingId" : "AAAAA".
you need to check for another match for booking status after $lookup like below
db.getCollection('invoice').aggregate([
{
$match: {
dueDate: {$gte: 1483596800},
dueDate: {$lte: 1583596800}
}
},
{
$lookup: {
from: "booking",
localField: "bookingId",
foreignField: "_id",
as: "booking"
}
},
{
$match: {
"booking.status": {$lt: 5},
}
}
])

using match for both linked collection of mongo in lookup

I have two collections - orders, feedback
Orders:
{
"restaurantId" : NumberInt(138),
"referenceNo" : "1980DBF5",
"orderId" : "1045593",
"userId" : NumberInt(6664960),
"userEmail" : "user#g.com",
"firstName" : "User"
}
Feedbacks:
{
"rating" : NumberInt(4),
"additionalComments" : "it is working",
"referenceNo" : "7D02097F",
"productId" : NumberInt(1),
"restaurantId" : NumberInt(138),
"orderType" : "1"
}
I need to make a join on these two collections.
Also, there will be filter inputs on rating, referenceNo, userEmail, firstName.
How can I use match to get data from two collections?
This is my aggregate query:
[
{
"$lookup":
{
"from": "orders",
"localField": "referenceNo",
"foreignField": "referenceNo",
"as": "data"
}
}
]
I am using this query on feedback model.
The data that I get is:
{
"rating" : NumberInt(4),
"additionalComments" : "it is working",
"referenceNo" : "7D02097F",
"productId" : NumberInt(1),
"restaurantId" : NumberInt(138),
"orderType" : "1"
"data": [{
"restaurantId" : NumberInt(138),
"referenceNo" : "1980DBF5",
"orderId" : "1045593",
"userId" : NumberInt(6664960),
"userEmail" : "user#g.com",
"firstName" : "User"
}]
}
Also, would it be possible to add limits here?
Earlier I was using this on orders -
mQuery.skip(Number(paginate.offset)).limit(Number(paginate.limit));
Check if this helps....
db.feedbacks.aggregate([ {
$lookup:
{
from: "users",
localField: "whatever",
foreignField: "whatever",
as: "data"
}},
{
$unwind: "$data"
},
{
$match:
{
"data.orderId":"1045593"} //conditions
},
{
$limit:1 //limit
}
]);