Group document mongodb - mongodb

I'm trying to group document with mongodb but couldn't figure out how.
I have a document looks like this
{
_id: ObjectId('12345'),
username: 'asd',
region: 'zxc',
amount: 500,
type: 'car',
brand: 'vent',
order: 2
},
{
_id: ObjectId('98283'),
username: 'asd',
region: 'zxc',
amount: 1500,
type: 'car',
brand: 'dinosaur',
order: 1
}
And I want to group the document by username, region, type and make a new sub document from the result and order the sub-document ascending by the order. Also calculate the amount as a totalAmount. Which looks like this.
{
username: 'asd',
region: 'zxc',
type: 'car',
cart: [
{
brand: 'dinosaur',
amount: 1500
},
{
brand: 'vent',
amount: 500
}
],
totalAmount: 2000
}
I could only do this so far
db.test.aggregate([
{
$group: {
_id: {username: "$username"},
region: {$first: "$region"},
type: {$first: "$type"},
totalAmount: {$sum: "$amount"}
}
}
])
Thanks

You should put all of the fields you want to group on in the _id.
Use $push to collect values into an array, and $sum to compute the total:
db.collection.aggregate([
{
$group: {
_id: {
username: "$username",
region: "$region",
type: "$type"
},
cart: {
$push: {
brand: "$brand",
amount: "$amount"
}
},
total: {
$sum: "$amount"
}
}
}
])
Playground

Related

create index for mongodb collection

I have a MongoDB collection
{
id: String,
country: String,
createdAt: Date,
...
}
What is the right indices for the collection using this aggregate?
.aggregate([
{ $match: { country: "US" } },
{ $sort: { createdAt: -1 } },
{
$group: {
_id: { id: '$id' },
totalPrice: { $first: '$totalPrice' },
},
},
])
I have these indices on the schema
schema.index({ country: 1 });
schema.index({ createdAt: 1 });
schema.index({ country: 1, id: 1, createdAt: 1 });
But I think something is not healty

MongoDB SELECT * GROUP BY

I am playing around with MongoDB trying to figure out how to do a simple
SELECT * FROM data GROUP BY userid
But I can't figure out how? I have a collection like
data=[{
_id: "Kcs93S4R9v",
userid: "KqDuEwgv",
time: 1584353953159,
content: {}
}, {
_id: "3d0c4375",
userid: "LqDuEwgv",
time: 1584353953159,
content: {}
}, {
_id: "574ee87",
userid: "LqDuEwgv",
time: 1584353953159,
content: {}
}, {
_id: "Pcs93S4R9v",
userid: "KqDuEwgv",
time: 1584353953159,
content: {}
}]
I want the output to be like
[{
_id: "Kcs93S4R9v",
userid: "KqDuEwgv",
time: 1584353953159,
content: [{}, {}]
}, {
_id: "574ee87",
userid: "LqDuEwgv",
time: 1584353953159,
content: [{}, {}]
}]
But I can't seem to figure it out. Is there any way to do this with MongoDB?
You need to use $group operator in aggregation. Like below:
db.collection.aggregate([
{
$group: {
_id: "$userid",
time: {
$first: "$time"
},
content: {
$push: "$content"
}
}
}
])
MongoPlayGroundLink
Edit:
To first match the documents with the time field, you can use the $match operator,
db.collection.aggregate([
{
$match: {
time: 1584353953159
}
},
{
$group: {
_id: "$userid",
time: {
$first: "$time"
},
content: {
$push: "$content"
}
}
}
])

Aggregate string values to array of unique string values per field with mongo or mongoose and node.js

I need to aggregate "lastNames" and "occupations" for a "name" to get a result:
{
name: 'John',
occupations: ['software engineer', 'qa']
lastNames: ['Smith', 'Red', 'Doe']
}
input
name: 'John'
documents present in mongo:
{name: 'John', lastName: 'Smith', occupation: 'software engineer'}
{name: 'Steve', lastName: 'Smith', occupation: 'senior software engineer'}
{name: 'John', lastName: 'Doe', occupation: 'qa'}
{name: 'Steve', lastName: 'Doe', occupation: 'manager'}
{name: 'John', lastName: 'Red', occupation: 'software engineer'}
I started with this aggregation query:
Employees.aggregate([
{ $match: { name: name } },
{
$unwind: {
path: '$lastName',
},
},
{
$unwind: {
path: '$occupation',
},
},
{ $group: { _id: '$name' } },
]);
but this returns an empty array, so I kinda stuck as I never did aggregations before.
Is there a way to produce this required result?
Would be this one:
db.collection.aggregate([
{ $match: { name: "John" } },
{
$group: {
_id: "$name",
occupations: { $addToSet: "$occupation" },
lastNames: { $addToSet: "$lastName" },
}
},
{
$project: {
_id: 0,
name: "$_id",
occupations: 1,
lastNames: 2
}
}
])
Mongo playground

How to aggregate array of document in MongoDB

I have the following schema:
var orderSchema = new mongoose.Schema({
deleted: Boolean,
clientName: String,
clientPhone: String,
products: [{
name: String,
quantity: Number,
price: Number
}],
observations: String,
date: {
type: Date,
default: Date.now
},
seller: String,
orderNumber: Number,
total: Number
});
And I want to make an aggregate query that sums each product and add quantity*price to the total, and return me the total. However, I only know how to do it if I had multiple products, each one as a document, and then sum over all the documents but not this.
You can do this with $reduce :
db.collection.aggregate([{
$addFields: {
"total": {
$reduce: {
input: "$products",
initialValue: '$total',
in: { $add: [{ $multiply: ["$$this.quantity", "$$this.price"] }, '$$value'] }
}
}
}
}])
Test : MongoDB-Playground

mongo db aggregate keep fields after group

I have this aggregate:
[
{
$match: {_id: new ObjectId('xxx')}
},
{
$unwind: "$users"
},
{
$group: {
_id: '$users.status',
count: {$sum: 1}
}
},
{
$project: {
name: 1,
field1: 1,
field2: 1,
count: '$count'
}
}
]
The schema:
{
name: String,
field1: String,
field2: Schema.Types.Mixed,
users: [{
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
status: String
}]
}
The expected result:
{
name: 'NY',
field1: 'example',
field2: 'example2',
statuses: [
{
_id: 'ONLINE',
count: 20
},
{
_id: 'OFFLINE',
count: 120
},
{
_id: 'OTHER',
count: 230
}
]
}
This way I get group result just for the users statuses, and not for the other fields of the original object.