MongoError when trying to aggregate with collection relationship - mongodb

I am new to mongodb, using Mean stack from meanjs.org.
I have a model with a user collection relationship:
var MealSchema = new Schema({
mealDate: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Meal', MealSchema);
I had find an implementation that works:
var user = req.user;
Meal.find({
mealDate: {
$gte: minus8days.toDate(),
$lt: tomorrow.toDate()
},
user : user
}).exec(function (err, meals) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(meals);
}
});
But I need some grouping and aggregation so I am trying to change this code to use aggregate instead of a find, I've tried many combinations and I keep getting an error, basically the following implementation throws an error MongoError: Maximum call stack size exceeded
Meal.aggregate([
{
$match: {
$and: [
{
mealDate: {
$gte: minus8days.toDate(),
$lt: tomorrow.toDate()
}
}, { user: user }
]
}
}]...
Why user:user works with find and not with aggregate?
How can the aggregate approach be fixed?

Try this :
Meal.aggregate([
{
$match: {
mealDate: { $gte: minus8days.toDate(), $lt: tomorrow.toDate()},
user: user._id
}
}
], function(err, docs){
if(err) console.log("Error : " + JSON.stringify(err));
if(docs) console.log("Got the docs successfully : " + JSON.stringify(docs));
});

Related

MongoDB Aggregate Query Returning Empty Array

I'm new to Mongo and am trying to run an aggregate command on my model in my Node.js application (using Express). I'm trying to run the query for finding all users registered within the last month.
When I run User.find(), it returns all 2 users in the DB, so I know the users are definitely there.
However, when I run this, data is just an empty array. Is there a solution I'm missing here?
router.get("/stats", verifyTokenAndAdmin, async (req, res) => {
const date = new Date();
const lastYear = new Date(date.setFullYear(date.getFullYear() - 1));
try {
const data = await User.aggregate([
{ $match: { createdAt: { $gte: lastYear } } },
{
$project: {
month: { $month: "$createdAt" },
},
},
{
$group: {
_id: "$month",
total: { $sum: 1 },
},
},
]);
res.status(200).json(data)
} catch (err) {
res.status(500).json(err);
}
});
Also, the response is a 200 so no errors there.

How do I update an array using an object in mongodb?

I try to add an geojson object to an existing array in mongodb, this is my object that I'd like to add:
const location = {
type: "Feature",
properties: {
description: place.address,
name: place.name
},
geometry: {
coordinates: [
place.latLng.latitude,
place.latLng.longitude
],
type: "Point"
},
userIds: [userId],
id: place.id
}
I tried using this mongodb call without any effect:
db.collection.updateOne(
{ _id: "5e6e32051c9d4400128cba9c" },
{ $push: { features: location } },
function(err, result) {
if (err) {
reject(err);
}
console.log(result);
console.log("Added new location successfully");
resolve(true);
});
This does nothing. Features is an array which should contain geojson objects.
What do I do wrong?
Ok, I found the answer on this page: https://www.quora.com/How-do-I-update-a-document-in-mongodb-using-_id-as-query-parameter
In order to query for an _id you apparently have to convert the _id into an ObjectId first.
So I did this here:
const ObjectID = require('mongodb').ObjectID;
const id = ObjectID("5e6e32051c9d4400128cba9c");
And then:
db.collection.updateOne(
{ _id: id },
{ $push: { features: location } },
function(err, result) {
if (err) {
reject(err);
}
console.log(result);
console.log("Added new location successfully");
resolve(true);
});
This did work! :)

Mongoose findOneAndUpdate with $addToSet pushes duplicate

I have a schema such as
listSchema = new Schema({
...,
arts: [
{
...,
art: { type: Schema.Types.ObjectId, ref: 'Art', required: true },
note: Number
}
]
})
My goal is to find this document, push an object but without duplicate
The object look like
var art = { art: req.body.art, note: req.body.note }
The code I tried to use is
List.findOneAndUpdate({ _id: listId, user: req.myUser._id },
{ $addToSet: { arts: art} },
(err, list) => {
if (err) {
console.error(err);
return res.status(400).send()
} else {
if (list) {
console.log(list)
return res.status(200).json(list)
} else {
return res.status(404).send()
}
}
})
And yet there are multiple entries with the same Art id in my Arts array.
Also, the documentation isn't clear at all on which method to use to update something. Is this the correct way ? Or should I retrieve and then modify my object and .save() it ?
Found a recent link that came from this
List.findOneAndUpdate({ _id: listId, user: req.user._id, 'arts.art': artId }, { $set: { 'arts.$[elem]': artEntry } }, { arrayFilters: [{ 'elem.art': mongoose.Types.ObjectId(artId) }] })
artworkEntry being my modifications/push.
But the more I'm using Mongoose, the more it feels they want you to use .save() and modify the entries yourself using direct modification.
This might cause some concurrency but they introduced recently a, option to use on the schema { optimisticConcurrency: true } which might solve this problem.

MongoDB + Mongoose Aggregate w/ Asnyc

I've got the following route in my express file, which takes parameters passed in from a middleware function and queries my backend MongoDB database. But for some reason, it only ever returns an empty array.
I'd like to convert the Mongoose model that allows me to use aggregate functions into async/await to conform with the rest of my code. It's online here.
module.exports = {
search: asyncWrapper(async(req, res, next) => { // Retrieve and return documents from the database.
const {
filterTarget,
filter,
source,
minDate,
maxDate,
skip,
limit,
sortBy,
sortOrder
} = req.search;
try {
const mongoData = await Model.aggregate([
{
$match: {
date: {
$gt: minDate, // Filter out by time frame...
$lt: maxDate
}
}
},
{
$match: {
[filterTarget]: filter // Match search query....
}
},
{
$set: {
[filterTarget]: { $toLower: `$${filterTarget}` } // Necessary to ensure that sort works properly...
}
},
{
$sort: {
[sortBy]: sortOrder // Sort by date...
}
},
{
$group: {
_id: null,
data: { $push: "$$ROOT" }, // Push each document into the data array.
count: { $sum: 1 }
}
},
{
$project: {
_id: 0,
count: 1,
data: {
$slice: ["$data", skip, limit]
},
}
}
])
return res.status(200).json({ data: mongoData.data || [], count: mongoData.count || 0 });
} catch (err) {
next(err);
}
})
};
For some reason, the route is only returning an empty array every time. I've double and triple checked my variables, they are not the problem.
How can I use the Mongoose.aggregate() function in an async await route?

MongoDB: aggregate error when use Match and Group

I've model
var LogSchema = mongoose.Schema({
userId: String,
pageId: String,
tagId: String
}, {
timestamps: true
});
In code,
Log.aggregate([
{
$match: {
createdAt: {
$gte: new Date(strFrom),
$lte: new Date(strTo),
}
},
//$group: { _id: "$userId" },
}
], function (err, logs) {
if (err) {
res.status(500).send({ message: "error retrieving logs." });
} else {
res.send(logs);
}
});
When I execute code use $match, that's ok. Then, I add $group, I receive error
Error: Arguments must be aggregate pipeline operators
So, I remove $match, only use $grooup, code run ok. So, when I use both $match and $group, receive errors.
Please, give me ideas
Thank so much
You have a missing brace.
Log.aggregate([{
$match: {
createdAt: {
$gte: new Date(strFrom),
$lte: new Date(strTo),
}
},
{ <-- missing brace around your group
$group: { _id: "$userId" },
}],
function (err, logs) {
if (err) {
res.status(500).send({ message: "error retrieving logs." });
} else {
res.send(logs);
}
});