MongoDB aggregate error: expression must have exactly one field - mongodb

I have the following collection:
{
"_id" : ObjectId("5c3f744a0f05e90001e0085a"),
"date" : ISODate("2016-01-12T12:00:00.779Z"),
}
I need to group my documents by WEEK so I came up with this solution:
db.collection.aggregate([
{
$group : {
_id: { $year: { date: '$date' }, $week: { date: '$date' } },
date: { $first: '$date' }
}
},
{
$sort: { date: -1 }
}
]);
But when I run this I get this error:
An object representing an expression must have exactly one field: { $year: { date: "$date" }, $week: { date: "$date" } }
How can this be fixed or is there any better solution?
Thanks

Problem solved naming the expressions:
db.collection.aggregate([
{
$group : {
_id: {
year: { $year: { date: '$date' } },
week: { $week: { date: '$date' } }
},
date: { $first: '$date' }
}
},
{
$sort: { date: -1 }
}
]);

Related

MongoDB group ISODate but maintain date format

I know I can group data inside a collection by
{
$group: {
_id: {
day: {
$dayOfMonth: '$timeplay'
},
month: {
$month: '$timeplay'
},
year: {
$year: '$timeplay'
}
},
listeners: {
$sum: '$count'
}
}
However, it does not show the date in ISOdate format anymore which is what I need it to still do.
Is there a way to create ISOdate based on this information? As the output currently looks like the following
You can use $dateFromParts operator to convert to date from parts,
{
$group: {
_id: {
$dateFromParts: {
day: { $dayOfMonth: "$timeplay" },
month: { $month: "$timeplay" },
year: { $year: "$timeplay" }
}
},
listeners: { $sum: '$count' }
}
}
Playground
Use this
db.collection.aggregate([
{
$group: {
_id: { $dateTrunc: { date: "$timeplay", unit: "day" } },
listeners: { $sum: '$count' }
}
}
])

Group documents with MongoDB

I come from the world of relational databases and am having difficulty with a MongoDB query.
In my database I have telemetry documents with minute-by-minute records for each monitored system.
I'm tending to do a query that groups records by hour.
Below is a demonstration of the structure of my documents:
{
_id: ObjectId("61847b83618fc8a6fb368ab7"),
system_code: 22,
date: ISODate("2021-08-01T00:00:01.000Z"),
value1: 22.2372973251,
value2: 20
}
Here's the structure of the query I'm trying to run:
db.telemetry.aggregate([
{
$match: {
$and: [
{ system_code: 22 },
{ date: { $gte: ISODate("2021-08-01 00:00:00") } },
{ date: { $lte: ISODate("2021-08-01 02:00:00") } }
]
}
},
{
$addFields: {
italianDate: {
$dateToString: {
format: "%d/%m/%Y %H:00:00",
date: "$date"
}
}
}
},
{
$sort: {
italianDate: 1
}
},
{
$group: {
_id: {
year: { $year: "$date" },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" },
hour: { $hour: "$date" }
}
}
}
]);
The SQL query with PostgreSQL is exactly this:
SELECT TO_CHAR(t.date, 'YYYY-MM-DD HH24:00:00') AS italianDate, AVG(value1), AVG(value2) FROM telemetry t WHERE t.system_code = 22 AND t.date BETWEEN '2021-08-01 00:00:00' AND '2021-08-01 02:00:00' GROUP BY italianDate ORDER BY italianDate ASC
Thank you so much if you can help me.
You are actually pretty close. You just need to put the $avg inside your $group stage. Another thing is you need to pay attention to the date formats. Refer to this official MongoDB document for the formats.
db.telemetry.aggregate([
{
$match: {
system_code: 22,
date: {
$gte: ISODate("2021-08-01T00:00:00Z"),
$lte: ISODate("2021-08-01T02:00:00Z")
}
}
},
{
$addFields: {
italianDate: {
$dateToString: {
format: "%Y-%m-%d %H:00:00",
date: "$date"
}
}
}
},
{
$group: {
_id: "$italianDate",
avgValue1: {
$avg: "$value1"
},
avgValue2: {
$avg: "$value2"
}
}
},
{
$sort: {
_id: -1
}
}
])
Here is the Mongo playground for your reference.

Mongodb aggregate $group and count for date ranges

I have documents like these:
{
"_id" : ObjectId("5cc80389c723e046f504b5a9"),
"adddress" : "string",
"checkIn" : "2019-04-30T08:12:57.909Z"
},
{
"_id" : ObjectId("5cc995f5a6f3eb7c483b019f"),
"adddress" : "string",
"checkIn" : "2019-05-01T12:49:57.561Z"
}
I have tried aggrgation like this:
var start = new Date("2019-04-30T08:12:57.909Z");
var end = new Date("2019-05-01T12:49:57.561Z");
var pipeline = [
{
$match: {
checkIn: {
$gte: start,
$lte: end
}
}
},
{
$group: {
_id: {
year: {
$year: "$checkIn"
},
month: {
$month: "$checkIn"
},
day: {
$dayOfYear: "$checkIn"
}
},
count: {
$sum: 1
}
}
}];
db.collections.aggregate(pipeline).toArray()
Is it possible to count them by checkIn date and get result like this:
"_id": [{
"checkIn": "2019-03-15T00:00:00Z",
"count": 4
}, {
"checkIn": "2019-04-30T00:00:00Z",
"count": 1
}, {
"checkIn": "2019-05-10T00:00:00Z",
"count": 1
}],
The result is shown the total number of the day.
{$project: {
checkIn: { $dateToString: { format: '%Y-%m-%d', date: '$checkIn' } }
}},
{$group: {
_id: '$checkIn',
checkIn: {$first: '$checkIn'},
count: {$sum: 1}
}},
{$sort: {checkIn: 1}}
Try this: I have tested this query and its working.
db.sample.aggregate([{
$addFields: {
date: {
$dateFromString: {
dateString: "$checkIn"
}
}
}
},{
$match: {
date: {
$gte: start,
$lte: end
}
}
},
{
$addFields: {
dateString: {
$dateToString: {
format: "%Y-%m-%d",
date: "$date"
}
}
}
},
{
$group: {
_id: "$dateString",
count: {
$sum: 1
}
}
}
]);

Query for nested groups and push in mongodb

I am trying mongoDB for first time. I need to aggregate my data from one collection to another. Trying this code but it doesn't execute because of unexpected error :
"unexpected expression $group"
db.import.aggregate([{
$group: {
_id: {
day: "$Day",
month: "$Month",
year: "$Year"
},
manufacturers: {
$push: {
$group: {
_id: {
manID: "$Man_ID",
man_name: "$Man_Name"
},
types: {
$push: {
model_name: "$Model_name",
body_type: "$Body_type"
}
}
}
}
}
}
},
{ $out: "output_doc" }
], {
allowDiskUse: true,
cursor: {}
});
Expected Output:
["$Day","$Month","$Year",
["$Man_ID","$Man_Name",
["$Model_name","$Body_type"]
]
]
You can just push your new _id field and create your types array without any operator :
db.import.aggregate([{
$group: {
_id: {
day: "$Day",
month: "$Month",
year: "$Year"
},
manufacturers: {
$push: {
_id: {
manID: "$Man_ID",
man_name: "$Man_Name"
},
types: [{ model_name: "$Model_name", body_type: "$Body_type" }]
}
}
}
}])

Add static field to grouped data in Mongodb

How to add static field to result using group operation in mongodb. My query looks like:
db.sales.aggregate({
$group : {
_id: {
year: { $year: '$date' },
},
amount: { $sum: 1 }
}
});
Than I get result:
{
"result" : [
{
"_id" : {
"year" : 2013
},
"amount" : 43433
},
...
]
"ok" : 1
}
I need to add field called type with value 'year' in each object of the result.
I just need add project operation with literal 'year'. Query looks like:
db.sales.aggregate([
{
$group : {
_id: {
year: { $year: '$registrationDate' }
},
amount: { $sum: 1 }
},
},
{
$project: {
type: { $literal: 'year' },
}
}
]);
$addFields is available in version 3.4+ e.g.
db.sales.aggregate({
$group : {
_id: {
year: { $year: '$date' },
},
amount: { $sum: 1 }
},
{
$addFields: {
type: 'year'
}
}
});