How can I remove an object from an array? - mongodb

I want to remove an object from an array. Here is the schema I'm working with:
event: {
invitees: {
users : [{
user: {
type: String,
ref: 'User'
},
}],
}
}
The query I'm using is listed below, but it isn't working. Basically, nothing happens when I run this script.
Event.update(
{"_id": req.params.event_id},
{"$pull": {"invitees.users.user": req.params.user_id}},
{safe: true, upsert: true},
function (err, data) {
if (err) {
console.log(err);
}
return res.json({ success: true });
}
);
What am I doing wrong?

The field of the $pull operator identifies the array to pull the elements from that match its query.
So your update should look like this instead:
Event.update(
{"_id": req.params.event_id},
// { $pull: { <array field>: <query> } }
{"$pull": {"invitees.users": {"user": req.params.user_id}}},
{safe: true, upsert: true},
function (err, data) {
if (err) {
console.log(err);
}
return res.json({ success: true });
}
);

Related

How to change a document in mongodb with findOneAndUpdate depending if it's an insert or an update

I have this function that upserts in database.
upsert = (req, res) => {
return Promise.all(req.body.map(resource => {
return Resource.findOneAndUpdate({
resource_id: resource.id
},
{
$set: {
title: resource.title,
seller_id: resource.seller_id,
initial_quantity: resource.quantity,
quantity: 0
}
},
{
upsert: true,
new: true
});
}))
.then(
res.status(200).json({ message: "OK" })
)
.catch(err => {
console.log(err);
res.status(500).json({ message: "Error" });
});
}
It is working as expected. Now I want to be able to:
Save 0 in quantity, if its a new document
Save quantity(db) + resource.quantity (request), if it is an update
How could I do this?
Use the pipeline form of update to use aggregation operators in the update:
Resource.findOneAndUpdate(
{"resource_id": resource.id},
[{$set: {
quantity: {$cond: {
if: {$eq: [{$ifNull: ["$quantity","null"]}, "null"]},
then: 0,
else: {$sum: ["$quantity", resource.quantity]}
}},
title: resource.title,
seller_id: resource.seller_id,
initial_quantity: resource.quantity
}}],
{
upsert: true,
new: true
}
)
Playground

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! :)

Can't add array to mongodb

I'm trying to send an array to mongodb, but the res.json(user) returns an empty biddingGroup:[] and mongodb document never has field biddingGroup appear. I've looked at stack posts and have seen suggestions for schema.
I've tried
biddingGroup: [{type: String}],
biddingGroup: [String],
biddingGroup: {type: String},
I haven't found a working schema that captures the data yet.
I even hardcoded biddingGroup: ['test'] too, but it never shows up.
app.js
app.put('/api/listings/:id', (req, res) =>
Post.update({
id: req.query.id
}, {
$set: {
currentBid: req.query.currentBid,
lastBidTimeStamp: req.params.lastBidTimeStamp,
biddingGroup: ['test']
}
}, {
multi: false //set to false to ensure only one document gets updated
}).exec().then(data => {
console.log(data);
}, err => {
console.log(err);
})
);
Any help is appreciated.
You need to use exec() at the end to run the query. That is the function that actually runs the request and returns you the promise. Plus your usage of the update function in general is off.
Try this:
Post.update({
id: req.query.id
}, {
$set: {
currentBid: req.query.currentBid,
lastBidTimeStamp: req.params.lastBidTimeStamp,
biddingGroup: ['test']
}
}, {
multi: false //set to false to ensure only one document gets updated
}).exec().then(data => {
console.log(data);
}, err => {
console.log(err);
});

mongoose findOneAndUpdate query

I am using mongoose for mongodb queries.
My update query returns null.
What am I doing wrong?
The query is as follows:
Model.findOneAndUpdate(criteria, updatedDetails, { 'new': true})
Example -
I have a user profile which I need to update and send the updated profile back to frontend.
User.findOneAndUpdate({mobile: "9999999999999"}, { address: "test address" }, {'new': true} )
But the result comes null instead of the updated profile.
findOneAndUpdate is now desprecated
use update, here is sample code
exports.updateSomething = (req, res) => {
Model.update({
_id: req.params.id
}, {
$set: {
bla: req.body.bla
}
})
.then(data => {
return res.status(200).json({
success: true,
message: 'Updated successfully'
})
})
.catch(err => {
return res.status(200).json({
success: false,
message: err.message
})
})
}

like/dislike mongodb using bulk

let bulk = Card.collection.initializeOrderedBulkOp();
// if user doesn't exist in array
bulk.find({
'_id': mongoose.Types.ObjectId(card_id),
'likedBy': { '$ne': mongoose.Types.ObjectId(user_id) }
}).updateOne({
'$inc': { 'likes': 1 },
'$push': { 'likedBy': mongoose.Types.ObjectId(user_id) }
});
// if user exists in array
bulk.find({
"_id": mongoose.Types.ObjectId(card_id),
"likedBy": mongoose.Types.ObjectId(user_id)
}).updateOne({
"$inc": { "likes": -1 },
"$pull": { "likedBy": mongoose.Types.ObjectId(user_id) }
});
bulk.execute(function(response) {
console.log(response);
return res.json({
'state': true,
'msg': 'Successful',
})
});
The above is supposed to behave by incrementing or decrementing the likes field if the user id exists in the likedBy array.
However, both functions run, thus the last of the bulk gets to be the last action done. In the above, the end result is always zero.
I suspect the query matches a document always, thus the .updateOne() parts run on all.
Here's the schema:
var CardSchema = new Schema({
slug: {
type: String,
lowercase: true,
index: true
},
title: String,
content: String,
createdAt: {
type: Date,
default: Date.now,
},
updatedAt: {
type: Date,
},
options: [],
likedBy: [],
likes: Number,
createdBy: String,
featured: Boolean,
});
Is there a better mongo way to do the like/dislike thing?
Going with this for now. Too verbose, but works. I've created a like and dislike button separately in the UI, which calls two independent functions, but to same endpoint, with endpoint rigged like this:
let like = req.body.like;
// if request is a like
if (like) {
Card.update({
'_id': mongoose.Types.ObjectId(card_id),
'likedBy': { '$ne': mongoose.Types.ObjectId(user_id) }
}, {
'$inc': { 'likes': 1 },
'$push': { 'likedBy': mongoose.Types.ObjectId(user_id) }
}, function(err) {
if (err) {
console.log(err);
return res.json({
'state': false,
'msg': err
})
}
return res.json({
'state': true,
'msg': 'Liked',
})
})
} else if (!like) { // if request is dislike
Card.update({
'_id': mongoose.Types.ObjectId(card_id),
'likedBy': mongoose.Types.ObjectId(user_id)
}, {
'$inc': { 'likes': -1 },
'$pull': { 'likedBy': mongoose.Types.ObjectId(user_id) }
}, function(err,) {
if (err) {
console.log(err);
return res.json({
'state': false,
'msg': err
})
}
return res.json({
'state': true,
'msg': 'Disliked',
})
})
}
Then something like this makes the request,
likeCard(card_id: string, like: boolean) {
let param = {
card_id: card_id,
like: like
};
return this.http.post(AppSettings.API_ENDPOINT + '/card/like', JSON.stringify(param), { headers: this.headers })
.map((res) => {
return res
})
}