I have this and I cannot get it to work. Console.log logs null.
If I log before de update code it actually logs the item that im trying to edit. If I do it after the findOneAndUpdate() it returns null.
Edit 2:
I changed the mongoose method to findById and it worked. Still have one problem though. New code:
let promo = await Promo.findById(req.body._id)
console.log('Promo findById(promoId) => ' + promo)
console.log('Promo Fields => ' + JSON.stringify(promoFields))
if (promo) {
// Update
const promo = await Promo.findOneAndUpdate(
{ promo: req.body_id },
{ $set: promoFields },
{ new: true },
(err, doc) =>
console.log(err + ' <--- err ///// ' + doc + ' <--- doc ')
)
return res.json(promo)
Output:
[0] Promo findById(promoId) => { _id: 5cee8b0134349e1eec482053,
[0] title: 'Dos',
[0] subtitle: 'dos',
[0] desc: 'dos',
[0] __v: 0 }
[0] Promo Fields => {"title":"Dos","subtitle":"dos","desc":"dos"}
[0] null <--- err ///// { _id: 5cee6bcbcfd3f11d580aa715,
[0] new: false,
[0] desc: 'dos',
[0] subtitle: 'dos',
[0] title: 'Dos' } <--- doc
The problem now is no matter what item from the list I edit it always updates de first one. Can it be an id mismatch? If I debug the id from req, I have the correct id from the item selected.. don't know why it behaves this way.
Last but not least here's the reducer:
const initialState = {
promos: null
}
export default function(state = initialState, action) {
const { type, payload } = action
switch (type) {
case POST_PROMOS:
return {
...state,
...payload,
loading: false
}
default:
return state
}
}
I was wondering if I could in the reduce make something like
state.promos.filter(promo => promo._id !== payload)
and then generate a new array with the payload item. I'm mixing concepts?
Thank you in advance
Bingo!
It seems that req.body._id for some reason even though it was the Id from the desired editing item, it was not an ObjectId.
I let promoId = mongoDb.ObjectId(req.body._id) and then
promo = await Promo.findOneAndUpdate(
{ _id: promoId },
{ $set: promoFields },
{ new: true }
)
:)! Thanks
You should use $addToSet in place of $set and it will maybe work.
Related
I'm trying to make the bot basically edit the message of any specific case mentioned for example if i do -case 5 test it will look for case 5 and it's message. So far when i do it, it basically changes the recent case number message, instead of the one i want it to change. like if i do case 5 test and the latest case is #9, it will change 9 instead of 5.
This is how i send the message:
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id }, { $inc: { 'caseID': 1 } }, { new: true }, async function (err, doc) {
if (err) throw err;
if (!doc) return;
if (doc.modLog.enabled) {
if (msg.channel.guild.channels.get(doc.modLog.channelID)) {
let m = await msg.channel.guild.channels.get(doc.modLog.channelID).createMessage({
embed: {
title: `${action} | Case #${doc.caseID}`,
color: colour,
fields: [
{
name: 'User',
value: user,
inline: true
},
{
name: 'Moderator',
value: moderator ? moderator : 'No issuer.',
inline: true
},
{
name: 'Reason',
value: reason ? reason : 'No reason.'
}
]
}
});
doc.messageID = m.id;
doc.type = action;
doc.caseID = doc.caseID;
//doc.caseID = m.id
doc.moderatorID = moderator,
doc.targetID = user
doc.save();
}
}
})
that is how i send my message. And you can see i'm storing the things so when someone changes a specific case's reason, for example: case 5 spamming, i would want it to look for caseID 5, and then edit the message through it's ID. but i'm not sure how am i doing it wrong. I'm trying to make each case store it's own message ID and i would really appreciate any help. This is what i use to look for the case and edit's reason.
Modlog.findOne({ guildID: msg.guildID }, async (err, doc) => {
if (err) throw err;
if (!doc.modLog.enabled) return msg.channel.createMessage(`Modlog is not enabled in this server! ${this.emoji.cross}`);
if (isNaN(Number(caseID))) return msg.channel.createMessage(`Case \`#${caseID}\` was not a number! ${this.emoji.cross}`);
if (doc.caseID === undefined) return msg.channel.createMessage(`Couldn\'t find case \`#${caseID}\`! ${this.emoji.cross}`);
const moderator = this.bot.users.get(doc.moderatorID) || {
username: 'Unknown User',
discriminator: '0000'
}
const target = this.bot.users.get(doc.targetID) || {
username: 'Unknown User',
discriminator: '0000'
}
let embed = {
title: `${doc.type} | Case #${doc.caseID}`,
fields: [
{
name: 'User',
value: `${target.username}#${target.discriminator} (${target.id})`,
inline: true
},
{
name: 'Moderator',
value: `${moderator.username}#${moderator.discriminator} (${moderator.id})`,
inline: true
},
{
name: 'Reason',
value: reason
}
]
};
try {
await this.bot.editMessage(doc.modLog.channelID, doc.messageID, { embed: embed });
await msg.channel.createMessage(`Case **#${caseID}** has been updated. ${this.emoji.tick}`);
} catch (e) {
await msg.channel.createMessage(`I\'m unable to edit that case or it has been deleted. ${this.emoji.cross}`);
}
});```
Solution: Search for Case ID
It seems you didn't look for the case ID, and only looked for the guild's ID in the filter parameter.
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id }, { ... }, { ... }, ... {
...
}
In your code, only guildID was passed into the filter parameter. This causes Mongoose to look for the most recently initialized document for the server. For your case, you should also pass caseID into the filter parameter.
Modlog.findOneAndUpdate({ guildID: msg.channel.guild.id, caseID: caseIDArg }, { ... }, { ... }, ... {
...
}
Replace caseIDArg with your supposed caseID argument in the message's content. For example, args[1] or however you programmed your argument handler to work.
Hope this helped to answer your question!
I have this array list of objects.
var list = [{
'ID':1,
'name' : 'Vikas Yadav',
'mobile':8095638475,
'sent':false
},
{
'ID':2,
'name' : 'Rajat Shukla',
'mobile':7486903546,
'sent':false
},
{
'ID':3,
'name' : 'Munna Bhaiya',
'mobile':9056284550,
'sent':false
},
{
'ID':4,
'name' : 'Guddu Pandit',
'mobile':7780543209,
'sent':false
},
{
'ID':5,
'name' : 'Srivani Iyer',
'mobile':8880976501,
'sent':false
}];
Now I want to push two more datas in specific element of this array via forLoop as:
var timeAndOTPArray = {
"time" : new Date(),
"OTP": req.params.ran
}
I am retrieving the list data via cookies into one of the route.
Below is the code I am trying to push the element according to the matching condition.
var lists = req.cookies.list;
Object.keys(lists).forEach(function(item) {
if(req.params.ID == lists[item].ID){ //look for match with name
(lists[item]).push(timeAndOTPArray);
newAddedList.push(lists[item]);
console.log(item, lists[item]);
}
});
Perhaps it's not the correct way. Please help!
Wish you a happy and a prosperous Diwali.
Cheers!
You can use findIndex and append to update the object into list like this:
//List only with ID, easier to read the code
var list = [{'ID':1,},{'ID':2,}]
//your object
var timeAndOTPArray = {
"time" : new Date(),
"OTP": "otp"
}
//Index where object with ID == 2 is
var index = list.findIndex(obj => obj.ID == 2);
//Append the 'timeAndOTPArray' properties into the object itself
list[index] = {"time": timeAndOTPArray.time, "OTP":timeAndOTPArray.OTP, ...list[index]}
console.log(list)
I guess this will help
var lists = req.cookies.list;
Object.keys(lists).forEach(function(item) {
if(req.params.ID == lists[item].ID){ //look for match with ID
Object.keys(timeAndOTPArray).forEach(key=>{
lists[item][key]=timeAndOTPArray[key];
})
}
});
Good evening) I can advice you the best option is update with map
const listItems = [
{
ID: 1,
name: 'Vikas Yadav',
mobile: 8095638475,
sent: false,
},
{
ID: 2,
name: 'Rajat Shukla',
mobile: 7486903546,
sent: false,
},
{
ID: 3,
name: 'Munna Bhaiya',
mobile: 9056284550,
sent: false,
},
{
ID: 4,
name: 'Guddu Pandit',
mobile: 7780543209,
sent: false,
},
{
ID: 5,
name: 'Srivani Iyer',
mobile: 8880976501,
sent: false,
},
];
const paramId = 4;
const result = listItems.map((item) => {
if (paramId === item.ID) {
return {
...item,
time: new Date(),
OTP: 'smth',
};
}
return item;
});
console.log('result', result);
for appending, you can do this,
lists[index] = Object.assign(lists[index], timeAndOTPArray);
If you are using es6,
lists[index] = {...lists[index], timeAndOTPArray};
Here lists is an array of objects.
so lists[item] is an object, so you cant push an object to an object.
In your code timeAndOTPArray is an object.
In your lists object, initialize an empty array called timeAndOTPArray
var index = lists.findIndex(function(item){ return item.ID == req.params.ID});
lists[index].timeAndOTPArray.push(timeAndOTPArray);
I got a route in express that get 2 different array of object from mongoDb and then return a new "contributions" array after i've added some data into it from "projectAll"
Here is one contributions object:
{
_id: "5f5b095f01ba8e40769f7301",
libId: "5f5a7a7701ba8e40769f72fb",
totalPaidAmount: 10000,
transactionId: "pi_1HQ4hVGmJhXXrXOXnr0pkXkv",
cart: [
{
_id: "5f5b095f01ba8e40769f7302",
amount: 5000,
projectId: "5f5b086601ba8e40769f72fe"
},
{
_id: "5f5b095f01ba8e40769f7303",
amount: 5000,
projectId: "5f5b08ae01ba8e40769f7300"
}
],
__v: 0
}
And one projectAll object:
{
projectCover: { id: "211290" },
title: "My title 2",
funded: 11000,
description: "Desc",
_id: "5f5b08ae01ba8e40769f7300",
libId: "5f5a7a7701ba8e40769f72fb",
__v: 0
}
I need to add projectAll.title and projectAll.projectCover into each contributions.cart objects.
To do so I match contribution.cart.projectId with projectAll._id.
router.get("/contributions/:id", async (req, res) => {
const id = req.params.id
try {
const contributions = await Contribution.find({id})
const projectAll = await Project.find({id})
const updatedContribution = contributions.map((contribution) => {
// Go through each cart of each contribution
const updatedCart = contribution.cart.map((cartItem) => {
// Find matching project
const matchingProject = projectAll.find((project) => {
// project OK =====> console.log(project)
// projectAll OK =====> console.log(projectAll)
// cartItem OK =====> console.log(cartItem)
return project._id === cartItem.projectId;
});
// Here return undefined =====> console.log(matchingProject)
const {projectCover, title} = matchingProject
return {...cartItem, projectCover, title
}
})
return { ...contribution, cart: updatedCart
}
})
res.send(updatedContribution)
} catch (err) {
res.status(500).send(err)
}
this code work perfectly in my codeSandBox : https://codesandbox.io/s/contribution-map-projects-vhv8z?file=/src/index.js
But in my express + mongoose environment I get undefined for matchingProject (i added comments in the code to show from where I get unwanted result)
Does anybody know why it doesn't work ?
Thanks a lot !
EDIT: console.log(typeof project._id, typeof cartItem.projectId) return object object
whereas in codesandbox those are strings.
Since they are both ObjectIds you can use mongoose equals() functions - so project._id.equals(cartItem.projectId). You cannot compare them, cause you'd compare their object reference. So either the above function will work or project._id.toString() === cartItem.projectId.toString()
I'm using mongoose to handle my DB queries. I'm trying to update a set of records entirely using this method. Mode code looks like this:
// prepare database query
const filter = { type: 'company' };
const update = req.body.payload; // payload contains the array of objects (i.e. updated records)
const options = { new: true, runValidators: true }
// find and update the taxonomy record
await Taxonomy.updateMany(filter, update, options);
But whenever I run this query I'm getting following error in the console:
Error [MongooseError]: Invalid update pipeline operator: "_id"
I suppose there is something wrong in my update payload. The req.body.payload looks like this:
[
{
_id: '5ef3d08c745428001d92f896',
type: 'company',
name: 'Company Size',
__v: 0
},
{
_id: '5ef3cdc5745428001d92f893',
type: 'company',
name: 'Company Industry',
__v: 0
}
]
Can you please tell me what actually is wrong here?
This is not the right usage of updateMany() - it is aimed to update many documents with a single change.
To update many documents use bulkwrite() (docs) :
async function myUpdateMany(Model, objectsArray) {
try {
let ops = []
for (let obj of (objectsArray || [])) {
ops.push({
updateOne: {
filter: { platformId: obj.platformId },
update: obj,
upsert: false, // set "true" if you want to add a new document if it doesn't exist
}
})
}
Model.bulkWrite(ops, { ordered: false });
} catch (err) {
throw Error("myUpdateMany error: " + err)
}
}
Regarding runValidators, according to this, it seems to work by default.
I am developing an app and I am using MEAN stack. I have values saved in a database using MongoDB. I want to use those values to make API calls but only if a value is null. Now it is successfully getting those values from the database and making the calls to the API but I don't know how to check if the value is null, I have tried basically everything but I think I don't understand completely NodeJS and that it is asynchronous. This is the code that works but doesn't check if the value is null:
var makeApiCalls = function (workerId) {
var Model = mongoose.model('Tweet'.concat(workerId), Tweet.tweetSchema);
return Model.find({},{ _id: 1, message: 1}).then(messages =>
Promise.all(
messages.map(({ _id, message }) =>
api.sentiment(message).then(result =>
Model.findOneAndUpdate({ _id }, { resultOfTheCall: result }, { new: true })
.then( updated => { console.log(updated); return updated })
)
)
)
)
};
The mongoose model has a field called resultOfTheCall and I need to check if that value is null and only in that case, I want to make a call to the API with the field message.
This is the console.log of one of the message:
{
_id: 5b85c83b413a2b1473e7122a,
date: 'Tue Aug 28 22:10:02 +0000 2018',
message: 'la gente quiere y no viene',
resultOfTheCall: 0.5931016939587707,
__v: 0 }
Simply filter the messages before making the Promise.all.
var makeApiCalls = function(workerId) {
var Model = mongoose.model('Tweet'.concat(workerId), Tweet.tweetSchema);
return Model.find({}, {
_id: 1,
message: 1,
resultOfTheCall: 1
}).then(messages => {
// filter the mssages here those for which to make the call and the others
var toCallArray = messages.filter(x => x.resultOfTheCall == null)
var noCallArray = messages.filter(x => x.resultOfTheCall != null)
// now do the calls for only those which do not have resultOfTheCall
return Promise.all(
toCallArray.map(({_id, message}) =>
api.sentiment(message).then(result =>
Model.findOneAndUpdate({
_id
}, {
resultOfTheCall: result
}, {
new: true
})
.then(updated => {
console.log(updated);
return [...noCallArray, ...toCallArray]
})
)
)
)
})
};