Can't add array to mongodb - 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);
});

Related

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.

Update query adding ObjectIDs to array twice

I am working on a table planner application where guests can be assigned to tables. The table model has the following Schema:
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const tableSchema = new mongoose.Schema({
name: {
type: String,
required: 'Please provide the name of the table',
trim: true,
},
capacity: {
type: Number,
required: 'Please provide the capacity of the table',
},
guests: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Guest',
}],
});
module.exports = mongoose.model('Table', tableSchema);
Guests can be dragged and dropped in the App (using React DND) to "Table" React components. Upon being dropped on a table, an Axios POST request is made to a Node.js method to update the Database and add the guest's Object ID to an array within the Table model:
exports.updateTableGuests = async (req, res) => {
console.log(req.body.guestId);
await Table.findOneAndUpdate(
{ name: req.body.tablename },
{ $push: { guests: req.body.guestId } },
{ safe: true, upsert: true },
(err) => {
if (err) {
console.log(err);
} else {
// do stuff
}
},
);
res.send('back');
};
This is working as expected, except that with each dropped guest, the Table model's guests array is updated with the same guest Object ID twice? Does anyone know why this would be?
I have tried logging the req.body.guestID to ensure that it is a single value and also to check that this function is not being called twice. But neither of those tests brought unexpected results. I therefore suspect something is wrong with my findOneAndUpdate query?
Don't use $push operator here, you need to use $addToSet operator instead...
The $push operator can update the array with same value many times
where as The $addToSet operator adds a value to an array unless the
value is already present.
exports.updateTableGuests = async (req, res) => {
console.log(req.body.guestId);
await Table.findOneAndUpdate(
{ name: req.body.tablename },
{ $addToSet : { guests: req.body.guestId } },
{ safe: true, upsert: true },
(err) => {
if (err) {
console.log(err);
} else {
// do stuff
}
},
);
res.send('back');
};
I am not sure if addToSet is the best solution because the query being executed twice.
If you used a callback and a promise simultaneously, it would make the query executes twice.
So choosing one of them would make it works fine.
Like below:
async updateField({ fieldName, shop_id, item }) {
return Shop.findByIdAndUpdate(
shop_id,
{ $push: { menuItems: item } },
{ upsert: true, new: true }
);
}

How can I remove an object from an array?

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 });
}
);

Populating nested array with ObjectIDs

Trying to populate an array of ObjectID's within my schema. I've looked around at similar answers but it seems everyone is doing it slightly differently and I haven't been able to find a solution myself.
My schema looks like this:
var GameSchema = new Schema({
title: String,
description: String,
location: String,
created_on: { type: Date, default: Date.now },
active: { type: Boolean, default: true },
accepting_players: { type: Boolean, default: true },
players: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
admins: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
So far I've been trying to populate it like this, which obviously isn't working
exports.getAdmins = function(req, res) {
Game.findById(req.params.id)
.populate('admins')
.exec(function(err, game) {
return res.json(200, game.admins);
});
};
I hate to add to the list of population questions, but I've looked at many and haven't found a solution. Any help is greatly appreciated!
Edit:
Here's how I am adding admins to the document
// Add admin to game
exports.addAdmin = function(req, res) {
Game.findByIdAndUpdate(
req.params.id,
{ $push: { 'admins': req.params.user_id }},
function(err, game) {
if(err) { return handleError(res, err); }
if(!game) { return res.send(404); }
return res.json(200, game.admins);
});
};
Well I went back to mongoose documentation, and decided to change how I looked up a game by an ID and then populated the response.
Now my working function looks like this:
// Returns admins in a game
exports.getAdmins = function(req, res) {
Game.findById(req.params.id, function(err, game) {
if(err) { return handleError(res, err); }
if(!game) { return res.send(404); }
Game.populate(game, { path: 'admins' }, function(err, game) {
return res.json(200, game);
});
});
};
The issue I was having was that I was trying to call the .populate function directly with the .findById method, but that doesn't work because I found on mongoose's documentation the the populate method need the callback function to work, so I just added that and voila, it returned my User object.
to populate an array, you just have to put model name field after path field like this :
Game.findById(req.params.id)
.populate({path: 'admins', model: 'AdminsModel'})
.exec(function(err, game){...});
it works perfectly on my projects...

How can I update multiple documents in mongoose?

I found the following script:
Device.find(function(err, devices) {
devices.forEach(function(device) {
device.cid = '';
device.save();
});
});
MongoDB has the "multi" flag for an update over multiple documents but I wasn't able to get this working with mongoose. Is this not yet supported or am I doing something wrong?
Device.update({}, {cid: ''}, false, true, function (err) {
//...
});
Currently I believe that update() in Mongoose has some problems, see:
https://groups.google.com/forum/#%21topic/mongoose-orm/G8i9S7E8Erg
and https://groups.google.com/d/topic/mongoose-orm/K5pSHT4hJ_A/discussion.
However, check the docs for update: http://mongoosejs.com/docs/api.html (its under Model). The definition is:
Earlier Solution(Depreciated after mongoose 5+ version)
Model.update = function (query, doc, options, callback) { ... }
You need to pass the options inside an object, so your code would be:
Model.update = function ({}, {cid: ''}, {multi: true}, function(err) { ... });
New Solution
Model.updateMany = function (query, doc, callback) { ... }
Model.updateMany = function ({}, {cid: ''}, function(err) { ... });
I believe that Mongoose wraps your cid in a $set, so this is not the same as running that same update in the mongo shell. If you ran that in the shell then all documents would be replaced by one with a single cid: ''.
Those answers are deprecated. This is the actual solution:
Device.updateMany({}, { cid: '' });
You have to use the multi: true option
Device.update({},{cid: ''},{multi: true});
as mentioned in the mongoose documents this is how we do this:
db.collection.updateMany(condition, update, options, callback function)
so this is an example based on the docs:
// creating arguments
let conditions = {};
let update = {
$set : {
title : req.body.title,
description : req.body.description,
markdown : req.body.markdown
}
};
let options = { multi: true, upsert: true };
// update_many :)
YourCollection.updateMany(
conditions, update, options,(err, doc) => {
console.log(req.body);
if(!err) {
res.redirect('/articles');
}
else {
if(err.name == "ValidationError"){
handleValidationError(err , req.body);
res.redirect('/new-post');
}else {
res.redirect('/');
}
}
});
this worked fine for me, I hope it helps :)
await Device.updateMany({_id: {$in: cid}},{ $set: {columnNameHere: "columnValueHere"}},{multi:true,upsert: true,new: true});
as #sina mentioned:
let conditions = {};
let options = { multi: true, upsert: true };
Device.updateMany(conditions , { cid: '' },options );
you can add a callback function after options but it's not necessary.
You can try the following way
try {
const icMessages = await IcMessages.updateMany({
room: req.params.room
}, {
"$set": {
seen_status_2: "0"
}
}, {
"multi": true
});
res.json(icMessages)
} catch (err) {
console.log(err.message)
res.status(500).json({
message: err.message
})
}