Push data in mongodb use value from another field - mongodb

I use mongoose for push data(use a value from rank_num field) to a field like this:
ListM.findOneAndUpdate({userId: req.body.userId},
[{
$push: {
listData: {
...req.body.musicToAdd,
pos: "$rank_num"
}
}
}])
And not work..., i dont know how to add value of another field in $push. Help me! thank you

If you want to add one value into your array field, try this. (rank_num is field name and req.body.musicToAdd is a value to be pushed.)
ListM.findOneAndUpdate(
{ userId: req.body.userId },
{ $push: { "rank_num": req.body.musicToAdd} },
{ safe: true, new: true }
).then((res) => {
console.log("updated result is", res);
}).catch((error) => {
console.log("error is", error);
});
If you want to push array to array field, try this. (listData is field name and req.body.musicToAdd is array to pushed.
ListM.findById(req.body.userId).then((res) => {
if (!res) return;
res.listData.push(...req.body.musicToAdd);
res.save();
return true;
})
catch((error) => {
console.log("error is", error);
});

Related

Pulling an object from user Model using $pull , having issues with multiple object items

I am trying to delete a post object from a user model, I hold these refrences to the post they have created, this is how I am trying to currently pull the post
userModel.findOneAndUpdate(
{ email: req.query.email, posts: req.query.postid },
// { $pull: { posts: req.query.postid } },
{ $pull: { posts : { number: mongoose.Types.ObjectId(req.query.postid) } }},
{ new: true },
function (error, user) {
if (error) {
res.json("error in /testing backend ===",error)
}
console.log(`Post id ===== ${req.query.postid}`);
console.log(`Email===== ${req.query.email}`);
console.log(`returning user====${user}`)
res.json('Successfully updated user');
}
);
this is how I have created the post
userModel.findOne({ email: req.body.author }, function(error, user) {
const locationURL = req.files.map((item) => item.location);
postModel.create({ ...req.body, image: locationURL }, (error, returnedDocuments) => {
if (error) {
throw new Error(error);
}
user.posts.push({ number: returnedDocuments._id, title: req.body.title, image: locationURL });
user.save((err) => {
console.log(err);
});
});
I originally had only 1 item pushed into the user model, but added a few more items, then I was having issues pulling the object, thanks for your help.
this is from my DB as to my posts array
For an array of objects, you can pull your desired document using the positional operator { "<array>.$" : value }.
{ $pull: { posts.$.number : req.query.postid }}
You can check out the docs on positional operators to learn more.

Using mongoose lean after saving

So I am trying to add a key to a returned post. But I can't seem to get lean() to work. How can I manipulate the returned post after save?
I was thinking maybe I need to add lean to my findById like this Post.findById(req.params.id).lean().then(). But that didn't work, plus that only makes the first initial post mutable. It will say
post.save is not a function
if I do it like Post.findById(req.params.id).lean().then() as well
I want to only return the object about to be sent back to the client, I do not want they key saved in the actual document.
Post.findById(req.params.id)
.then(post => {
if (
post.likes.filter(like => like.user.toString() === req.user.id)
.length === 0
) {
return res
.status(400)
.json({ notliked: "You have not yet liked this post" });
}
// Get remove index
const removeIndex = post.likes
.map(item => item.user.toString())
.indexOf(req.user.id);
// Splice out of array
post.likes.splice(removeIndex, 1);
// Save
post.save().then(post => {
post["liked"] = false; <-------
res.json(post);
});
})
edit
Post.findById(req.params.id)
.lean()
.then(post => {
if (
post.likes.filter(like => like.user.toString() === req.user.id)
.length === 0
) {
return res
.status(400)
.json({ notliked: "You have not yet liked this post" });
}
// Get remove index
const removeIndex = post.likes
.map(item => item.user.toString())
.indexOf(req.user.id);
// Splice out of array
post.likes.splice(removeIndex, 1);
post["liked"] = false;
res.json(post);
// Save
post.save();
})
gives error
post.save is not a function
You can simply do this by searching for the req.user.id inside the indexOf likes array
Post.findOne({ _id: req.params.id }).lean().then((post) => {
if (post.likes.indexOf(req.user.id) !== -1) {
post.isLiked = true
}
post.isLiked = false
res.json(post)
})
Far better with the aggregation
Post.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(req.user.id) }},
{ "$addFields": {
"isLiked": { "$in": [mongoose.Types.ObjectId(req.user.id), "$likes"] }
}}
])
EDIT :- If you want to update document then use update query
Post.findOneAndUpdate(
{ _id: req.params.id },
{ $pull: { likes: { user: req.user.id } }},
{ new: true }
).then((post) => {
res.json(post)
})
Post Schema for likes
...
likes: [
{
user: {
type: Schema.Types.ObjectId,
ref: "users"
}
}
]
...

Mongoose query using if else possible?

I have this Schema:
const guestSchema = new Schema({
id: String,
cart: [
{
product: {
type: mongoose.Schema.ObjectId,
ref: "products"
},
quantity: Number
}
]
});
I have this query:
Guest.findOneAndUpdate(
{ id: req.sessionID },
{
$cond: [
{ "cart.product": { $ne: req.body.itemID } },
{ $push: { "cart": { product: req.body.itemID, quantity: 1 } } },
{ $inc: { "cart.quantity": 1 } }
]
},
{ upsert: true, new: true }
).exec(function(err, docs) {
err ? console.log(err) : res.send(docs);
});
Basically, what I'm trying to do is update based on a condition. I tried using $cond, but found out that operator isn't used for querys like I'm doing.
Based on this:
{ $cond: [ <boolean-expression>, <true-case>, <false-case> ] }
I want something similar to the functionality of this operator for my query.
Let's break down my condition:
For my boolean expression: I want to check if req.body.itemID is $ne to any of the values in my cart
If true then: $push the itemID and quantity into the cart
Else (then item already exists): $inc the quantity by 1
Question: How would achieve this result? Do I need to make two seperate querys? I'm trying to avoid doing that if possible
I went through all their Update Field Operators, and there's probably no way to do this in the way I want.
I wonder why there is no $cond for update operators. Nonetheless, I have the solution to what I wanted the functionality accomplish. Just not in the elegant fashion that I would like it.
Guest.findOneAndUpdate(
{ id: req.sessionID },
{ id: req.sessionID }, //This is here in case need to upsert new guest
{ upsert: true, new: true }
).exec(function(err, docs) {
if (err) {
console.log(err);
} else {
//Find the index of the item in my cart
//Returns (-1) if not found
const item = doc.cart.findIndex(
item => item.product == req.body.itemID
);
if (item !== -1) {
//Item found, so increment quantity by 1
doc.cart[item].quantity += 1;
} else {
//Item not found, so push into cart array
doc.cart.push({ product: req.body.itemID, quantity: 1 });
}
doc.save();
}
});
This type of logic does not belong within the database query. It should happen in the application layer. MongoDB is also very fast at retrieving and updating single records with an index so that should not be a concern.
Please try doing something like this:
try {
const guest = await Guest.findOne().where({
id: req.sessionID
}).exec();
// your cond logic, and update the object
await guest.save();
res.status(200).json(guest);
} catch (error) {
handleError(res, error.message);
}

How to update a field using its previous value in MongoDB/Mongoose [duplicate]

This question already has answers here:
Update MongoDB field using value of another field
(12 answers)
Closed 5 years ago.
I know I can do an update using $set:
Contact.update({
_id: request.id
}, {
$set: { name: newNameValue }
}, {
upsert: false
}, function(err) { ... });
But in this case, instead of passing newNameValue, I'd like to use the previous name value to compute the new one. Let's say I want to capitalize the old name, something like:
Contact.update({
_id: request.id
}, {
$set: { name: $old.name.toUpperCase() }
}, {
upsert: false
}, function(err) { ... });
I think this has already been answered here: How to add new data to current string in MongoDB?, so please, check that for a more detailed answer, but anyway, in short, you can't do that with a single query.
The way to do it using Mongoose, as shown in this official Mongoose example:
Contact.findById(request.id, (err, contract) => {
if (err) return handleError(err);
contract.name = contract.name.toUpperCase();
contract.save((err, contractContract) => {
if (err) return handleError(err);
...
});
});
as far as I know it's not possible. You would need to find and then update
Contact
.find({
_id: request.id
})
.exec(function(err, data) {
if (err) {
return ...;
}
Contact.findByIdAndUpdate(request.id, {
$set: {
name: data.name.toUpperCase()
}
}, {
new: true
}, function(err, doc) {
if (err) return ...;
console.log(doc)
});
}

fail to update documents with cursor.forEach

This Meteor client code does not update the documents found as expected. The console.log(res) prints '0' when there are documents to be updated.
Why and how to fix it? Thanks
MyCollection.find({
class: 'check-filter'
}).forEach((obj) => {
MyCollecction.update({
obj
}, {
$set: {
class: ''
}
}, (err, res) => {
if (!err) {
console.log(res);
}
});
});
Change your selector to use the object's _id:
MyCollection.find({ class: 'check-filter' }).forEach(obj => {
MyCollection.update(obj._id, { $set: { class: '' }}, (err, res) => {
if (!err) {
console.log(res);
}
});
});
Also you have a typo where you're trying to do MyCollecction.update instead of MyCollection.update