mongooseJS returning an object after update? - mongodb

Is it possible to return a document after updating it?
my current code looks something like this:
module.exports.updateEmail = function(id, data, callback) {
User.findByIdAndUpdate( id, {
$set: { "email": email }
}, callback);
}
how would I pull the User document and pass it back?

add {new : true} update option, to return the updated document, the callback will have the updated document you can return it
module.exports.updateEmail = function(id, data, callback) {
User.findByIdAndUpdate( id,
{$set: { "email": email }},
{new : true}, // to return updated document
callback
);
}

Related

How to return an aggregate query in an Apollo resolver (Meteor/Apollo/Graphql)?

I'm trying to run a query with an aggregate in Meteor and I've not been able to figure out how to return an aggregation query.
In my GraphQL schema:
type UserRelation {
date: String!
userID: String!
}
type UserData {
userID: String!
description: String!
friends_list: [UserRelation]!
}
extend type Query {
getFriends(userID: String!, friendID: String): [UserRelation]
}
In my resolvers.js:
import UserData from "./userData";
export default {
Query: {
getFriends(obj, args, context) {
if (args.friendID) return UserData.rawCollection().aggregate([
{
$match: {
_id: 'cuS7KebEQDRv2iFpJ'
}
},
{
$unwind: '$friends_list'
},
{
$match: {
'friends_list._id': '8GW4gjwWhkEexfndd'
}
}
]);
return UserData.findOne({ userID: args.userID }, {fields: {_id: 0, friends_list: 1 }}).friends_list;
}
}
}
In this hardcoded example, I have the following document in my database:
And I want to return the entire document with ONLY the user with a matched _id and whose friends_list has another user with the second matched _id. So this way I can return the entire document with only that 1 element in the friends_list array instead of all other elements as well.
Now this query works fine in Robo3T (a MongoDB GUI), but there's an issue with the return statement when I run it in Graphiql as an error is thrown which states:
"Expected Iterable, but did not find one for field \"Query.getFriends\"." When I log that statement, I see a Mongo AggregationCursor. But I'm not sure how I should "convert" this to a type that the resolver can return properly.
Any help is appreciated, thank you!
I don't know if I actually figured it out because I need to test it more, but this is working so far, in my resolvers.js I have:
import UserData from "./userData";
async function getFriend(userID, friendID) {
return UserData.rawCollection().aggregate([
{
$match: {
_id: userID
}
},
{
$unwind: '$friends_list'
},
{
$match: {
'friends_list._id': friendID
}
}
]).toArray();
}
export default {
Query: {
async getFriends(obj, args, context) {
if (args.friendID){
const result = await getFriend(args.userID, args.friendID);
return result[0].friends_list;
}
return UserData.findOne({ userID: args.userID }, {fields: {_id: 0, friends_list: 1 }}).friends_list;
}
}
}
By making it async I was able to get this done. Not sure what implications this has, but so far it works. If anyone is able to review this and give some critique to improve this it would be sincerely appreciated, as any information about this has been excruciatingly difficult to find, as I have not seen any use-cases of this so far.

can't update DB using put request in express.js

I'm trying to update the languages_known through post request to the mongodb collection using the body of the request but its not updating i'm newbie any help would be really appreciated.
mongodb document :
{
"_id": {
"$oid": "5d63e81c342987154cdc698e"
},
"name": "anjana",
"email": "anju#gmail.com",
"age": "22",
"languages_known": [
"Bengali",
"Kannada"
],
"phone": "684684684846"
}
server code :
app.put('/students/add',function(req,res){
var myobj={
$set:{_id:require('mongodb').ObjectID(req.body.id),languages_known:req.body.remove}
}
db.collection('students').updateOne({languages_known:req.body.add},myobj,function(err,result){
if(err){throw err}
console.log("updated")
})
})
request body :
{
"id":"5d63e81c342987154cdc698e",
"remove": ["Bengali", "Kannada"],
"add": ["Tamil", "Punjabi"]
}
I've expected to update the languages_known field using this req through postman to this id
Ok this issue is with the query, you can't update _id of a document like that, also as your requirement is not to do that, Please try this :
server code :
// replace languages_known with new languages based on _id, in case if you wanted to update the array you can use $push
app.put('/students/add', function (req, res) {
const id = require('mongodb').ObjectID(req.body.id)
let updateQuery = {
$set: { languages_known: req.body.add }
}
db.collection('students').updateOne({ _id: id }, updateQuery, function (err, result) {
if (err) { throw err }
console.log("updated")
})
})

Mongoose: how to insert a new field in Object?

I need to add a new field in the Object, but the old field is removed and inserted a new one. upsert:true has no effect.
await Model.findOne({userID:message.author.id}, async function(err, user) {
if (!user.servers_xp[message.guild.id]) {
await Model.updateOne({userID:message.author.id}, { $set: {
servers_xp: {[message.guild.id]: {level: 1, curentxp: 0}}
} }, {upsert:true})
}
});
On your $set statement in the update operation you override the entire server_xp field with a new object: {[message.guild.id]: {level: 1, curentxp: 0}}, so your server_xp field will have exactly this object.
Instead, in order to add new fields to the already exists object (server_xp), you should use the dot notation, this way the object will be updated and not overwritten..
Like this:
await Model.findOne({userID: message.author.id}, async function (err, user) {
if (!user.servers_xp[message.guild.id]) {
let updateObj = {};
updateObj[`server_xp.${message.guild.id}`] = {level: 1, curentxp: 0};
await Model.updateOne({userID: message.author.id}, {
$set: updateObj
},
}
});
I don't think you need the upsert here. upsert is for new documents (when the filter/query find nothing).

Return only created subdocument mongoose

I need to push a new document into an array and use his _id.
Right now im using findOneAndUpdate, i know i can use { new: true } but i only need the created document and not the parent document.
this is my code so far
User.findOneAndUpdate(
{
'posts._id': req.params.id
},
{
$push: {
'posts.$.comments': {
from: {
_id: req.user._id,
username: req.user.username,
},
body: req.body.commentBody
}
}
},
err => {
if (err) console.log(err)
// Do something with ObjectId
}
);
Thanks in advance.
findOneAndUpdate callback gives you the updated document.
You have the Post's _id. You can use that to find the post to which you are adding the comment to. As you are pushing the comment, it will be the last element in the post array.
var mypost = doc.posts.find(function(post){
return post._id.toString()==req.params.id
});
console.log(mypost.comments[mypost.comments.length]._id)

How to save / update multiple documents in mongoose

I am reading all documents of a specific schema from Mongoose. Now in my program I am doing some modifications to the results I got from Mongoose over time. Something like this:
var model = mongoose.model("Doc", docSchema);
model.find(function(err, result){
// for each result do some modifications
});
How can I send all the results back to the database to be saved? Currently I am iterating the documents and doing a save() on every document. I think there must be a better way. But currently I only find information on updating documents IN the database without returning them. Or bulk updates which do the SAME to update to each document.
You can use update query with multi:true which update all documents in your db.
please find below reference code,
model.update({ "_id": id }, { $set: { "Key": "Value" } }, { multi: true }, function (err, records) {
if (err || !records) {
return res.json({ status: 500, message: "Unable to update documents." });
} else {
return res.json({ status: 200, message: "success" });
}
});
If you are trying to make the same change to each document in the results, you could do something like this:
model.update({ _id: { $in: results.map(doc=>doc._id) }}, { yourField: 'new value' }, { multi: true })