Mongoose cant fetch all objects from array - node.js

I have a mongoose query that should fetch all Participants in certain Event model, but I only get back one participant. I tried the $all method, still no result.
query:
Participants.find({'_id': {$all: event.participants}}, (err, participants) => {
if (err) {
return console.log(err);
}
console.log(participants);
});
output:
[ { createdAt: 1970-01-01T00:00:00.011Z,
_id: 5be7fc340016817bcb4ybdfc,
name: 'TEST',
ticket: 5be7fc340016817bc44fbdfb,
email: 'test#test.com',
__v: 0 } ]
expected output
[ { createdAt: 1970-01-01T00:00:00.011Z,
_id: 5be7fc340016817bcb4fbdfc,
name: 'TEST',
ticket: 5be7fc3400d16817bcb4fbdfb,
email: 'rene370d#gmail.com',
__v: 0 },
{ createdAt: 1970-01-01T00:00:00.011Z,
_id: 5be7fc340016817bcb4fbdfc,
name: 'Another test',
ticket: 5be7fc3s40016817bcb4fbdfb,
email: 'another#emai.com',
__v: 0 } ]
event.participants
participants:{
type: [mongoose.Schema.Types.ObjectId],
ref: 'ParticipantSchema'
}

From the documentation:
The $all operator selects the documents where the value of a field is an array that contains all the specified elements.
So it doesn't make much sense to use it to get all documents for a certain model.
Instead, use the $in operator
Participants.find({ _id: { $in: event.participants } }, (err, participants) => {
if (err) {
return console.log(err);
}
console.log(participants);
});

Related

I have problem updating a subdocument in an array of subdocuments in MongoDB

I have problems updating a subdocument in an array of subdocuments.
Here is my data structure in the users collection:
{
favorites: [
{
id: new ObjectId("639707f36bf9468265d91810"),
expiresAt: 1671361200000,
reminder: false
},
{
id: new ObjectId("637cc4c986b4fbec43579e1f"),
expiresAt: 1672603200000,
reminder: false
}
],
_id: new ObjectId("637e8af40e43f40373686da2"),
email: 'something#something.com',
forename: 'something',
surname: 'something',
role: 'user',
password: 'something',
__v: 0
}
My Schema is:
const userSchema = new Schema({
email: String,
forename: String,
surname: String,
role: String,
password: String,
favorites: {
id: { type: Schema.Types.ObjectId, ref: "Event" },
expiresAt: Number,
reminder: Boolean,
},
});
I want to update the reminder field in a subdocument based on the subdocument’s id.
I’ve tried following approaches:
1.
User.findOneAndUpdate(
{ _id: req.body.user, "favorites.id": { $eq: BSON.ObjectId(req.body.id) } },
{ $set: { "favorites.$.reminder": true } },
).setOptions({ sanitizeFilter: true });
Here nothing happens. It finds the document but does not update it.
2.
User.findOneAndUpdate(
{ _id: req.body.user },
{ $set: { "favorites.$[elem].reminder": true } },
{
arrayFilters: [{ "elem.id": { $eq: BSON.ObjectId(req.body.id) } }],
returnNewDocument: true,
}
).setOptions({ sanitizeFilter: true });
Here it returns an error: “Error: Could not find path “favorites.0.id” in schema”
I cannot find where is my mistake? Any help is much appreciated!
P.S.
Mongo version is 5.0.14
Try to use updateMany instead.
User.updateMany(
{
_id: userId,
"favorites.id": eventId
},
{
$set: {
"favorites.$.reminder": true
}
},
function(err, res) {
if (err) {
// Handle error
} else {
// Handle success
}
}
);
I think you can adapt the query to your calling method findOneAndUpdate. But it's enough to you.

Need to push data in nested subdocument array

I need to push data in nested subdocument array(replyComment):
This is an example of a document from my database:
{
comments: [
{
replyComment: [],
_id: 601a673735644c83e0aa1be3,
username: 'xyz123#gmail.com',
email: 'xyz213#gmail.com',
comment: 'test123'
},
{
replyComment: [],
_id: 601a6c94d1653c618c75ceae,
username: 'xyz123#gmail.com',
email: 'xyz123#gmail.com',
comment: 'reply test'
}
],
_id: 601a3b8038b13e70405cf9ea,
title: 'latest test',
snippet: 'latest test snippet',
body: 'latest test body',
createdAt: 2021-02-03T05:58:24.123Z,
updatedAt: 2021-02-03T12:28:33.237Z,
__v: 7
}
I am also mentioning my code snippet:
app.post('/:id/replyComment',(req,res) => {
const replyComm = new Comment(req.body);
Topic.findById(req.params.id)
.then((result) => {
topic = result,
console.log(topic);
topic.update({_id:req.params.id, "comments._id": req.body.comment_id},
{ $push: {"comments.$.replyComment": {replyComment: replyComm}}}
)
topic.save()
.then((result) => {
// console.log(result);
res.send({
text: "Replied",
})
})
.catch((err) => {
console.log(err);
});
})
});
By running the request I am not getting any error but still the same documented is getting printed on my terminal and there is no change in "replyComment" subarray.
Pls suggest how to make this work or any alternate method.
I prefer to use objects instead of arrays by converting objects to the array Object.keys(data.comments)
{
comments:
{
'601a673735644c83e0aa1be3':{
username: 'samyakjain971#gmail.com',
email: 'samyakjain971#gmail.com',
comment: 'test123'
}
},
{
'601a6c94d1653c618c75ceae':{
username: 'samyakjain971#gmail.com',
email: 'samyakjain971#gmail.com',
comment: 'reply test'
}
},
_id: 601a3b8038b13e70405cf9ea,
title: 'latest test',
snippet: 'latest test snippet',
body: 'latest test body',
createdAt: 2021-02-03T05:58:24.123Z,
updatedAt: 2021-02-03T12:28:33.237Z,
__v: 7
}
define topic variable like this :
let topic = result;
console.log(topic);
topic.update({_id:req.params.id, "comments._id": req.body.comment_id},
{ $push: {"comments.$.replyComment": {replyComment: replyComm}}}
)

Mongodb - aggregate by embedded document id overwrite the outer document _id

I have this kind of 'comment' model:
{ _id: <comment-id>,
user: {
id: { type: Schema.ObjectId, ref: 'User', required: true },
name: String
},
sharedToUsers: [{ type: Schema.ObjectId, ref: 'User' }],
repliedToUsers: [{ type: Schema.ObjectId, ref: 'User' }],
}
And I want to query for all comments which pass the following conditions:
sharedToUsers array is empty
repliedToUsers array is empty
But also, I want the result to contain only 1 comment (the latest comment) per user by the user id.
I've tried to create this aggregate (Node.js, mongoose):
Comment.aggregate(
{ $match: { "sharedToUsers": [], "repliedToUsers": [] } },
{
$group: {
_id: "$user.id",
user: { $first: "$user" },
}
},
function (err, result) {
console.log(result);
if (!err) {
res.send(result);
} else {
res.status(500).send({err: err});
}
});
It is actually working, but the serious problem is that the results comments _id field is been overwritten by the nested user _id.
How can I keep the aggregate working but not to overwrite the original comment _id field?
Thanks
Ok, I have a solution.
All I wanted is to group by _id but to return the result documents with their _id field (which is been overwritten when using $group operator).
What I did is like wdberkley said, I've added comment_id : { "$first" : "$_id" } but then I wanted not to return the comment_id field (because it doesn't fit my model) so I've created a $project which put the comment_id in the regular _id field.
This is basically how it looks:
Comment.aggregate(
{
$match: {
"sharedToUsers": [], "repliedToUsers": []
}
},
{
$group: {
comment_id: { $last: "$_id" },
_id: "$user.id",
content: { $last: "$content" },
urlId: { $last: "$urlId" },
user: { $last: "$user" }
}
},
{
$project: {
_id: "$comment_id",
content: "$content",
urlId: "$urlId",
user: "$user"
}
},
{ $skip: parsedFromIndex },
{ $limit: (parsedNumOfComments - parsedFromIndex) },
function (err, result) {
console.log(result);
if (!err) {
Comment.populate(result, { path: "urlId"}, function(err, comments) {
if (!err) {
res.send(comments);
} else {
res.status(500).send({err: err});
}
});
} else {
res.status(500).send({err: err});
}
});
thanks wdbkerkley!

Updating mongoose schema fields concurrently

I'm trying to update a mongoose schema. Basically I have two api's '/follow/:user_id' and '/unfollow/:user_id'. What I'm trying to achieve is whenever user A follows user B , user B followers field in mongoose will increment as one.
As for now I managed to get only following fields increment by one but not the followers fields.
schema.js
var UserSchema = new Schema({
name: String,
username: { type: String, required: true, index: { unique: true }},
password: { type: String, required: true, select: false },
followers: [{ type: Schema.Types.ObjectId, ref: 'User'}],
following: [{ type: Schema.Types.ObjectId, ref: 'User'}],
followersCount: Number,
followingCount: Number
});
Updated version: I tried my solution, but whenever I post it, it just fetching the data ( I tried the api's on POSTMAN chrome app ).
api.js
// follow a user
apiRouter.post('/follow/:user_id', function(req, res) {
// find a current user that has logged in
User.update(
{
_id: req.decoded.id,
following: { $ne: req.params.user_id }
},
{
$push: { following: req.params.user_id},
$inc: { followingCount: 1}
},
function(err) {
if (err) {
res.send(err);
return;
}
User.update(
{
_id: req.params.user_id,
followers: { $ne: req.decoded.id }
},
{
$push: { followers: req.decoded.id },
$inc: { followersCount: 1}
}
), function(err) {
if(err) return res.send(err);
res.json({ message: "Successfully Followed!" });
}
});
});
These codes only manage to increment the user's following fields, and without duplication. How do I update logged in user's following fields and as well as other user's followers fields at the same time?
Updated version: it keeps fetching the data.
May be this is how you want to. Instead of using update, you can also use findOneAndUpdate from Mongoose queries.
apiRouter.post('/follow/:user_id', function(req, res) {
User.findOneAndUpdate(
{
_id: req.decoded.id
},
{
$push: {following: req.params.user_id},
$inc: {followingCount: 1}
},
function (err, user) {
if (err)
res.send(err);
User.findOneAndUpdate(
{
_id: req.params.user_id
},
{
$push: {followers: req.decoded.id},
$inc: {followersCount: 1}
},
function (err, anotherUser) {
if (err)
res.send(err);
res.json({message: "Successfully Followed!"})
});
});
}
If you are not sure about it is updated or not, you can just use console.log() for both user and anotherUser variables to see changes.

Mongodb using addtoSet to ensure there are no duplicates

Using mongoose against mongodb 2.6 - another issue raised that sounds similar to mine;
https://github.com/LearnBoost/mongoose/issues/1677
I have this piece of code:
$addToSet: {
invite_list: {
$each : [
{ email: 'test#test.com' },
{ email: 'test#test.com' },
{ email: 'test#test.com' },
{ email: 'test#test.com' }]
}
}
which should only store one item but instead its storing 4!
However, changing the query to this
$addToSet: {
invite_list: {
$each : [
'test#test.com',
'test#test.com',
'test#test.com',
'test#test.com' ]
}
}
returns one item, as expected.
Model schema field:
invite_list: [{email: {type: String, trim: true}}],
The query looks like this;
UserModel.findOneAndUpdate(
{
_id: req.params.id,
},
{
$addToSet: {invite_list: { $each : [{ email: 'test#test.com' },
{ email: 'test#test.com' },
{ email: 'test#test.com' },
{ email: 'test#test.com' }] }}
}, function (err, user) {
// morel logic here...
return res.status(200).json(user);
});
http://docs.mongodb.org/manual/reference/operator/update/addToSet/
Is there something Im missing.
Thanks.
J
After reading this, it got me thinking;
Stop Mongoose from creating _id property for sub-document array items
Found a fix;
Model now looks like this;
var subSchema = new mongoose.Schema({email: {type: String, trim: true, _id: false}},{ _id : false })
invite_list: [subSchema],
Works as expected...
J

Resources