I'm quite new to NoSQL and struggling to write this query I am using Mongoose on Node.js
What I want to achieve is to get ONE latest result based on Group of Device ID. I have no trouble writing this in SQL but having hard time doing it in NoSQL.
Here is the Model setup
_id DeviceID Coordinate:{lat, long}
1 2 lat: 1, long: 2
2 3 lat: 2, long: 3
3 1 lat: 3, long: 3
4 3 lat: 5, long: 4
5 2 lat: 7, long: 5
6 2 lat: 9, long: 6
7 3 lat: 111, long: 7
8 2 lat: 113, long: 8
The output that I want is:
_id DeviceID Coordinate:{lat, long}
3 1 lat: 3, long: 3
7 3 lat: 111, long: 7
8 2 lat: 113, long: 8
This is what I have tried but the result I've got is undefined
Note: beginDayID
, endDayID
are variables of mongoose ObjectId represents the _id of beginning and end of day.
mongoose.model('GPSData').aggregate([
{$match: {_id:{$gte: beginDayID, $lt: endDayID}}},
{$unwind: "$Coordinates"},
{$project: {DeviceID: '$DeviceID' }},
{$group: { DeviceID: '$DeviceID', $lat: '$Coordinates.lat', $long: '$Coordinates.long'}}
], (e, data) => {
console.error(e)
console.log(data)
if (e) return callback(e, null);
return callback(null, data);
})
MongoDB find() method is used to select documents from a specified collection. It also set the cursor position to the selected document. The default find() method gets the documents from the start of the collection.
$first selects the first document from each output group: The _id: null group is included. When the accumulator field, $quantity in this example, is missing, $first returns null .
$$ROOT. The $$ROOT variable contains the source documents for the group. If you'd like to just pass them through unmodified, you can do this by $pushing $$ROOT into the output from the group.
This means $last returns the last order type for the documents between the current document and the end of the partition.
I assume you have documents somewhat similar to this
/* 1 */
{
"_id" : 1,
"DeviceID" : 1,
"Coordinate" : {
"lat" : 1,
"long" : 2
}
}
/* 2 */
{
"_id" : 2,
"DeviceID" : 2,
"Coordinate" : {
"lat" : 1,
"long" : 6
}
}
...
then an aggregation pipeline like this should work
mongoose.model('GPSData').aggregate([
{
$match: ... // your match filter criteria
},
{
$sort: {
_id: 1
}
},
{
$group: {
_id: '$DeviceID',
lastId: { $last: '$_id' },
lat: { $last: '$Coordinate.lat' },
long: { $last:'$Coordinate.long' }
}
},
{
$project: {
_id: '$lastId',
DeviceID: '$_id',
lat: 1,
long: 1
}
}
])
The output documents' shape look like this
/* 1 */
{
"_id" : 1,
"DeviceID" : 1,
"Coordinate" : {
"lat" : 1,
"long" : 2
}
}
/* 2 */
{
"_id" : 2,
"DeviceID" : 2,
"Coordinate" : {
"lat" : 1,
"long" : 6
}
}
Note the additional stage of $sort
as you have to specify an order when talking about keeping the 'last values'. You may have to specify another sorting if you have other requirements
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With