Updating two different documents in one line - node.js

I have the following code for updating two users, both with different id .
User.update(
{ id: req.body.myId },
{
$addToSet: { FriendIds: req.body.friendId }
},
function(err, user){
}
);
User.update(
{ id: req.body.friendId },
{
$addToSet: { FriendIds: req.body.myId }
},
function(err, user){
}
);
I could not find anything in the docs aside from updating two things with the same attribute by setting multi : true . However, the ids are different in this case, and it would be easier to error handle if I had them both being updated at once.

Why not take advantage of parallel operations in bluebird or using co
You can do something like :
co(function* () {
var res = yield {
1: User.update({ id: req.body.myId }, { $addToSet: { FriendIds: req.body.friendId }}).exec(),
2: User.update({ id: req.body.friendId },{$addToSet: { FriendIds: req.body.myId }}).exec(),
};
console.log(res); // { 1: Upate_response_for_1 , 2: Upate_response_for_2 }
}).catch(onerror);

Related

how can send new added item in nested object as response

I have a collection with name User in my mongodb for the example you can see in below a sample of saved user
{
_id: new ObjectId("61488f3892099143ca2b2bbc"),
name: 'test',
orders: [],
products: [
{
name: 'as',
image: '049fcd8d-f954-4aef-bd77-757af881f7c5.jpeg',
_id: new ObjectId("61531666ad63a47ed692c90b")
},
]
}
I have function with node.js that has responsible to add new product to selected user
async function addProduct(req, res, next) {
await User.findOneAndUpdate(
{ _id: req.params.userId },
{
$addToSet: {
products: {
...req.body,
image: req.file.filename,
},
},
}
);
return res.status(200).send();
}
but I want to send only new added product as response
please help me to solve this problem.
I recommend you to use the $push operator (doc):
{ $push: { <field1>: <value1>, ... } }
Using it with your example:
(async () => {
await User.findByIdAndUpdate(
'6153769ce997d65baf860cc7',
{
$push: {
products: {
name: 'as2',
image: '589fcd8d-f954-4aef-bd77-757af881f7c5.jpeg'
}
}
}
);
})();

MongoDB projection parameter not working in findOne()

I'm trying to use a projection parameter on findOne() to extract a single field from a document (stats) but it just seems to return the whole document. I'm using version "mongodb": "^3.4.1" in Node.js
This is the document structure
{ _id: 5e563015fa9a1a0134cac3cb,
username: 'user1',
password: '1234',
email: 'user#email.com',
stats:
{ totalViewed: 122,
totalUnique: 4,
tknow: 80,
tdknow: 42,
setCnt: 78 },
progress:
[ { cardId: 1001, knowCnt: 3, dknowCnt: 4 },
{ cardId: 1016, knowCnt: 0, dknowCnt: 0 } ] }
This is the code:
var findOneDoc = function() {
db.collection("testusers").findOne(
{ username: "user1" },
{ stats: 1 }, //field to return
function(err, result) {
if (err) {
console.log("Error: ", err);
}
console.log("Success: ", result);
}
);
};
findOneDoc();
I also tried:{$project: {stats: 1}}, to no avail
Thanks
Based on the documentation the .findOne() method takes options as a second parameter and it is recommended to use projection to define fields:
db.collection("testusers").findOne(
{ username: "user1" },
{ projection: { stats: 1 } },
function(err, result) { ... }
);
with findOne operations, the second parameter passed is an options parameter, so you should pass in your projects within the options parameter, like this:
query = { username: "user1" };
options = { projection: { stats: 1 }};
db.collection("testusers").findOne(query, options)
you can do it like mick said, with findOne
await db.collection("testusers").findOne(
{ username: "user1" },
{ projection: { stats: 1 } },
function(err, result) { ... }
);
or you can do it with find, like that
await db.collection("testusers")
.find({ username: "user1" })
.limit(1)
.project(["stats"])
.toArray()
you can add fields to the array project for more fields
findOne returns a document. use find() …..

Trying to update a subdocument in a parent document mongoose

i am trying to update or remove a subdocument from a parent document using mongoose.
My code:
editSubscription(req, res) {
const token = req.headers.authorization;
jwt.verify(token, req.app.get('yourSecretKey'), function (err, payload) {
userModel.update({ _id: payload.user._id, "subscriptions._id": req.params.id }, { "$set": { "subscriptions.$": req.body } }, function (err, obj) {
console.log(obj)
})
})
}
The output of the console.log is
{ n: 0, nModified: 0, ok: 1 }
How should i do this? i know if its modified the nModified returns a 1. I can't find any docs on how to approach this or solve it and all the solutions here on stackoverflow i already tried, nothing is working.
A sample of a document in my collection:
id: '5db990daa05aa90de0c8b86b',
user:
{ role: 'User',
subscriptions: [
{ active: true,
_id: '5dbad05aaf232e2bdc033339',
name: 'Basic Fit',
price: 20,
paymentDate: '07-11-2020',
created: '2019-10-31T12:15:22.360Z',
updated: '2019-10-31T12:15:22.360Z' },
{ active: true,
_id: '5dbad2568bf56255a0f39bc7',
name: 'Netflix',
price: 10,
paymentDate: '07-11-2019',
created: '2019-10-31T12:23:50.141Z',
updated: '2019-10-31T12:23:50.141Z' } ]
],
_id: '5db990daa05aa90de0c8b86b',
fullname: 'Test naam',
email: 'test1#mail.com',
password:
'$2a$10$VzBnIcVraIRdmzy6rPHOX.7gGOXToTBNISLEfi429OfpRx02FxCaO',
birthDate: '02-12-1988',
created: '2019-10-30T13:32:10.276Z',
updated: '2019-10-30T13:32:10.276Z',
__v: 0 },
payload.user._id == the verified logged in user ID
req.params.id is supposed to be the subscriptionId im trying to edit
Try this:
editSubscription(req, res) {
const token = req.headers.authorization;
jwt.verify(token, req.app.get('yourSecretKey'), function (err, payload) {
userModel.update({ _id: ObjectId(payload.user._id), "subscriptions._id": ObjectId(req.params.id) }, { "$set": { "subscriptions.$": req.body } }, function (err, obj) {
console.log(obj)
})
})
}
I tried and im getting a 500 error response back..
When i remove the 'req.params.id' and i do it like this:
userModel.updateOne({ _id: payload.user._id }, { "$set": { "subscriptions.0.price":
req.body.price} }).then(user => {
console.log(user)
}).catch(err => {
console.log(err)
})
Then it works but since i have multiple items in an array i do not want to update only the first one..
I tried using a filter in the $set operator but im getting errors all over the place..

Mongoose update returns undefined

How can I update a field with new properties that is initially set to be an empty object?
For example, I have the following schema:
import mongoose from 'mongoose';
var RunSchema = mongoose.Schema(
{
runId: { type: String },
reports: {
cookieSummary: {
name: String,
path: String
}
}
}
)
export default mongoose.model('Run', RunSchema);
And I'm trying to update the following document:
{
"_id": {
"$oid": "5a0565c2537e0b5d9d08ee6b"
},
"__v": 0,
"reports": {},
"runId": "8r4LNN3fRqd3qNgdW"
}
But when I run this code, it returns undefined:
Run.findOneAndUpdate({runId: '8r4LNN3fRqd3qNgdW'},
{
$set: {'reports.cookieSummary': { 'name': 'test' }},
}, (err, doc) => { console.log(doc) })
The object notation works after adding type to fields, like this: name: { type: String }
Try to use dot notation, as you're setting just one field:
Run.findOneAndUpdate(
{ runId: '8r4LNN3fRqd3qNgdW' },
{ $set: {'reports.cookieSummary.name': 'test' } },
(err, doc) => { console.log(doc) })
According to the docs, the command you're using should work but you write it wrongly. Try like this:
Run.findOneAndUpdate(
{ runId: '8r4LNN3fRqd3qNgdW' },
{ $set: { 'reports.cookieSummary': {'name': 'test'} } },
(err, doc) => { console.log(doc) })
if it does not work, maybe mongo expect that the object matches its schema when you use the command like this. But I don't think so.
Let me know.
Your query for update a document is good only the mistake is at the end of curly braces of $set. You entered un-necessary comma at the end that is actually creating problem in this case. So I suggest you to remove it and run this :
Run.findOneAndUpdate({runId: '8r4LNN3fRqd3qNgdW'},
{
$set: {'reports.cookieSummary': { 'name': 'test' }}
}, (err, doc) => { console.log(doc) });
and then see. Rest of your query is fine.
Hope It will work for you.
Thanks.
Try using below code, it will update the document and return the updated document.
var Q = require('q');
var deferred = Q.defer();
Run.findOneAndUpdate({ runId: '8r4LNN3fRqd3qNgdW' }, { $set: { 'reports.cookieSummary.name': 'test' } }, { new: true },
(err, doc) => {
console.log(doc);
deferred.resolve(doc);
});
return deferred.promise;
I made a small change. Test this solution.
Run.findOneAndUpdate({runId: '8r4LNN3fRqd3qNgdW'},
{
$set: {"reports": {'cookieSummary':{'name': 'test'}}},
}, (err, doc) => { console.log(doc) })

Mongoose update with limit

I am looking to update X documents all at once. The short is I basically need to randomly select N documents and then update them as "selected". I'm trying to design an API that needs to randomly distribute questions. I can not find a way to do this in mongoose I have tried:
update ends up selecting everything
Question
.update({}, {
$inc: {
answerCount: 1,
lockedCount: 1
},
$push:{
devices: deviceID
}
}, {multi:true})
.limit(4)
--- I also tried
Question
.find()
.sort({
answerCount: 1,
lockedCount: 1
})
.limit(req.query.limit || 4)
.update({}, {
$inc: {
answerCount: 1,
lockedCount: 1
},
$push:{
devices: deviceID
}
}, { multi: true }, callback);
Both resulted in updating all docs. Is there a way to push this down to mongoose without having to use map ? The other thing I did not mention is .update() without multi resulted in 1 document being updated.
You could also pull an array of _ids that you'd like to update then run the update query using $in. This will require two calls to the mongo however the updates will still be atomic:
Question.find().select("_id").limit(4).exec(function(err, questions) {
var q = Question.update({_id: {$in: questions}}, {
$inc: {answerCount: 1, lockedCount:1},
$push: {devices: deviceid}
}, {multi:true});
q.exec(function(err) {
console.log("Done");
});
});
So I did an simple map implementation and will use it unless someone can find a more efficient way to do it.
Question
.find({
devices: { $ne: deviceID}
},
{ name: true, _id: true})
.sort({
answerCount: 1,
lockedCount: 1
})
.limit(req.query.limit || 4)
.exec(updateAllFound );
function updateAllFound(err, questions) {
if (err) {
return handleError(res, err);
}
var ids = questions.map(function(item){
return item._id;
});
return Question.update({ _id: { $in: ids} } ,
{
$inc: {
answerCount: 1,
lockedCount: 1
},
$push:{
devices: deviceID
}
}, { multi: true }, getByDeviceID);
function getByDeviceID(){
return res.json(200, questions);
}
}

Resources