Nested array value comparison with another array value in mongoose using nodejs - node.js

How can I get addedproducts array elements where productids' of addedproducts array match with every id in productids' array of invitationfrom array(for a particular user email) in the below structure?
var UserSchema = new Schema(
{ email:
{ type: String,
unique: true,
required: true
},
addedproducts:[ {
name: String,
productid:String,
producttype:String
} ],
invitationfrom : [ {
fromemail: String,
productid:[String]
}]
}, {collection: 'user-data-db'});

Try this one
User.find({'addedproducts.productid': "123456"}, {'invitationfrom.productid': "123456"})
.exec(function (err, user) {
if (err) {
return res.status(500).json({message: err});
}
if (!user) {
return res.status(404).json({message: 'No Match Found'});
} else {
return res.status(200).json(user);
}
});

Related

Unique array in Mongoose is not throwing error when same key is stored again

I try to store friends in my friends collection. This collection contains a field userId which is an array of user ids. When I store the same id again I want mongoose to throw an error.
My friend schema looks like this:
const friendSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
userId: [{
type: mongoose.Schema.Types.ObjectID,
unique: true,
required: true,
ref: 'User',
}],
});
I am calling it like this:
Friends.findByIdAndUpdate({_id: req.userData.userId}, {$addToSet: { userId: req.body.id } }, {safe:false, upsert: true}, function (error, friend) {
if(error){
return res.status(500).json({
message: 'You already added this user as friend! ' +error,
});
}else if (!friend) {
return res.status(401).json({
message: 'Authentication failed',
});
} else {
Friends.
find({_id: req.userData.userId})
.populate('userId')
.exec(function(error, posts) {
if(!error) {
let returnValue = [];
posts.map((x)=>{
returnValue = x.userId;
})
return res.status(200).json(returnValue);
}else {
return res.status(400).json({message: error.message});
}
})
}

Mongoose: how to only populate, sort and return a nested object?

I have a User schema, with a messages array. The message array is filled by conversations id and referenced to a Conversation schema.
I want to fetch all conversations from a user, sort them by unread and then most recent messages. Finally, I must only return an array of lastMessage object.
For the moment, I have only managed to populate the whole user object.
Here is the Conversation Schema:
const conversationSchema = new mongoose.Schema(
{
name: { type: String, required: true, unique: true },
messages: [{ message: { type: String }, authorId: { type: String } }],
lastMessage: {
authorId: { type: String },
snippet: { type: String },
read: { type: Boolean },
},
},
{ timestamps: true }
);
conversationSchema.index({ name: 1 });
module.exports = mongoose.model("Conversation", conversationSchema);
And here is my code:
router.get("/conversations", async (req, res) => {
try {
const { userId } = req.query;
const user = await User.findById({ _id: userId }).populate("messages");
.sort({ updatedAt: 1, "lastMessage.read": 1 });
return res.json({ messages: user.messages });
} catch (err) {
console.log("error", err);
return res.json({ errorType: "unread-messages-list" });
}
});
How to do this?

NodeJS & Mongoose, update values in array of objects not working

I am struggling to update some specific arrays in my UserSchema with the mongoose function findByIdAndUpdate().
This is my UserSchema:
const UserSchema = new mongoose.Schema({
mail: {type: String, required: true, unique: true},
password: {type: String, required: true},
friends: [{id: String}],
prot: [{
id: String,
admin: Boolean,
}]
});
I only want to update the prot element, this is how I want todo this:
User.findByIdAndUpdate(req.body.userId, {
$set: { prot: [{ id: req.body.lockId, admin: req.body.isAdmin }] }, function(err, user) {
if (err) {
return res.status(500).send({
message: err.message || "Some error occured while updating user"
});
}
if (!user) {
return res.status(404).send({
message: "User not found"
});
}
return res.status(200).send(user);
}
})
But when I try to send a request via Postman, I didn't get an response or error..
FindByIdAndUpdate doesn't return updated document per default, you should add option {new:true}. You have mixed brackets too. Do it like below:
User.findByIdAndUpdate(
req.body.userId,
{
$set: {
prot: [{
id: req.body.lockId,
admin: req.body.isAdmin
}]
}
},
{ new: true },
function(err, user) {
if (err) {
return res.status(500).send({
message: err.message || "Some error occured while updating user"
});
}
if (!user) {
return res.status(404).send({
message: "User not found"
});
}
return res.status(200).send(user);
}
);
If you want to update a specific record inside an array of objects. You can do it like this.
User.update(
{ _id: req.body.userId,
prot:
{ $elemMatch: { id: req.body.lockId }}
},
{ $set:
{ prot: { admin: req.body.isAdmin }
}
},(error,result)=>{
if(error){
//handle error
}
console.log(result);
}
)

Failed to update single property by mongoose

Frist I have read and try the solution in the post of mongoose-and-partial-select-update.
However when I try to use the traditional style, query would work.
My schema:
var userSchema = mongoose.Schema({
local: {
email: {
type: String,
index: {
unique: true,
dropDups: true
}
},
password: String,
displayName: String,
avatar: {
type: String,
default: "./img/user.png"
},
role: {
type: String,
default: "student"
},
ask_history: [
{
question_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'questionAnswer'
},
favorite: Boolean,
ask_time: Date
}
],
interest: [String]
}
})
Working Update function:
User.findById(id, function(err, User) {
if (err) {
throw done(err);
}
if (!User) {
return;
}
User.local.role = "admin";
User.save(function(err, updatedUser) {
if (err) {
throw err
} else {
//good
}
})
});
However if I do this:
User.update({_id : id},
{$set{
local:{role:"admin"}
}
},function(...){...}
});
Code above will overwrite user into:
{
_id : "...",
local: {
role : "admin"
}
}
I read that $ will make the update only changing property, where I did wrong?
The positional operator $ works with array of subdocuments.
In your case you have a single sub-document, so the following should work:
User.update({_id : id},
{ $set
{
"local.role": "admin"
}
}, function(...){...}
});

Error:Can't canonicalize query: BadValue Unsupported projection option

User Schema
var UserSchema = new Schema({
name: String,
username: { type: String, required: true, index: { unique: true }},
password: { type: String, required: true, select: false},
favouriteid:[{eventid:String}]
});
Event Schema
var EventSchema=new Schema({
name:String,
location:{ type:String },
description:{type:String },
price: String,
rating: {
value: String,
count: {type: String, default: 10},
userrating: [{
uservalue: String,
userid: String
}]
},
imageurl:[String],
userimageurl:[String],
reviews:[{ userid:String,
username: String,
comment:String}]
});
POST METHOD to push the value of userid and uservalue in Event Schema.
api.post('/rateevent', function (req, res) {
var userid = req.body.userid;
var uservalue = req.body.uservalue;
var eventid = req.body.eventid;
Event.findById({_id: eventid},
{$push: {rating: {userrating: {uservalue: uservalue, userid: userid}}}},
{upsert: true},
function (err, events) {
if (err) {
res.send(err);
return;
}
else {
calculaterating(events);
}
});
function calculaterating(event) {
event.rating.count++;
event.rating.value = (event.rating.value * (event.rating.count - 1) + uservalue) / event.rating.count;
res.json("rating updated");
}
});
It is showing the following error:
{
"name": "MongoError",
"message": "Can't canonicalize query: BadValue Unsupported projection option: $push: { rating: { userrating: { uservalue: \"5\", userid: \"56593f3657e27af8245735d7\" } } }",
"$err": "Can't canonicalize query: BadValue Unsupported projection option: $push: { rating: { userrating: { uservalue: \"5\", userid: \"56593f3657e27af8245735d7\" } } }",
"code": 17287
}
Is the post method not correct? I have seen other mongodb documents but not able to find this type of thing. I am new to node js. Help me.
It should be Event.update instead of Event.findById, Also your push operation looks wrong. It should be like this:
Event.findOneAndUpdate(
{_id: eventid},
{$push: {'rating.userrating': {uservalue: uservalue, userid: userid}}},
{new: true},
function (err, events) {
if (err) {
res.send(err);
return;
}
else {
if(events.length > 0){
calculaterating(events);
}
else {
res.json({msg: "Nothing to update"});
}
}
});
function calculaterating(event) {
event = event[0]; //get the object from array
event.rating.count++;
event.rating.value = (event.rating.value * (event.rating.count - 1) + uservalue) / event.rating.count;
Event.update(
{_id: eventid},
{$set: {
'rating.count': event.rating.count,
'rating.value': event.rating.value
}},
function(err, response){
if (err) {
res.send(err);
return;
}
else {
res.json({msg: "rating updated"});
}
});
}
In events variable you will get the document that was updated in the new state. If you had passed {new: false} you will get the document as it was before the update.
in MY case
i was using the wrong method like below i was updating the record by
findOne , that can`t be possible , in my case , thats why issues
occurs
Solution: if you want to update the record , use .update() method,
and if you want to find records , then you can use .find() , .findOne() , don`t mismatch
domain.Cart.findOne({
UserId: req.body.UserId,
shopId: req.body.shopId,
},
{ $addToSet: { "productDetails": _productDetails } }
).exec(function (err, results) {
console.log(err, results)
callback(null, {
result: results,
msg: "productCount has been updated"
})
})

Resources