How can I update a property inside an object in Mongoose - javascript

i'm trying to update a property inside an object using $inc in mongoose. I've tried several ways but apparently the syntax is not valid.
this is the relevant part of the Schema:
stats: {
type: {
totalMatches: {
type: Number,
default: 0
},
totalWins: {
type: Number,
default: 0
},
totalRebuys: {
type: Number,
default: 0
},
totalTimesHosted: {
type: Number,
default: 0
},
averagePosition: {
type: Number,
default: 0
},
gainLossRatio: {
type: Number,
default: 0
},
totalFinishesForEachPosition: {
type: [Number],
default: [0]
}
}
}
});
const UserModel = mongoose.model("User", userSchema);
This is the part for the update, the syntax error is inside the $inc block:
UserModel.savePokerResultToPlayerData = (game) => {
_.each(game.results, (playerResult, index) => {
let resultToSave = {
matchId: game._id,
date: game.date,
ranking: index + 1,
prizeMoney: playerResult.prizeMoney,
rebuys: playerResult.rebuys,
isHostPlayer: game.host === playerResult._id
};
const statsObject = prepareStatsDataToBeUpdated(resultToSave);
UserModel.findByIdAndUpdate(
playerResult._id,
{
$push: { results: resultToSave },
$inc: {
stats.totalMatches: 1,
stats.totalWins: statsObject.totalWins,
stats.totalRebuys: statsObject.totalRebuys,
stats.totalTimesHosted: statsObject.totalTimesHosted
}
}
)
.exec()
.then()
.catch(err => {
console.log('error: ' + err);
});
});
};
prepareStatsDataToBeUpdated = (resultToSave) => {
return {
totalWins: resultToSave.ranking === 1 ? 1 : 0,
totalRebuys: resultToSave.rebuys,
totalTimesHosted: resultToSave.isHostPlayer ? 1 : 0
};
};
I've looked at a few similar questions here and tried the solution but all of them got me a syntax error.
I know i can find the related user, work on it and save it but i believe it loses the purpose of $inc and $push.

Probably you got syntax error about javascript.
It's forbidden to write invalid variable name on the left side of the ":" when you define object, here you use dot notation in place where have to be valid variable name or string:
stats.totalMatches: 1
please use quotes:
"stats.totalMatches": 1

Related

updating specific model keys depending on argument

So I'm trying to change a specific key in a model on my database given a specific argument in a function. I can of course do it as repeating if statements, but it's of course not very lucrative or sustainable. Given that in my actual application the keyX goes all the way up to 9, I'm not very enticed to solve this problem like this. The example below is of course a simpler enactment of my problem.
//model.js
const { DataTypes } = require('sequelize');
const db = require('../database/connection');
const model = db.define('exampleModel', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
key1: { type: DataTypes.STRING },
key2: { type: DataTypes.STRING },
key3: { type: DataTypes.STRING },
//keyN...
someotherKey: { type: DataTypes.ARRAY(DataTypes.JSON) }
});
module.exports = model
//insertions.js
const { model } = require('../models/model')
async function insert(argument) {
if(argument === 1) { model.update({ key1: 'something' }) }
if(argument === 2) { model.update({ key2: 'something else' }) }
if(argument === 3) { model.update({ key3: 'something else entirely' }) }
}
insert(2); //desired outcome here is the function only updating the text of key2
Essentially I want to change only a specific key depending on what my given argument for the function is. A fix i tried initially was:
const desiredKey = `key{argument}`
model.update({ [desiredKey]: "completely new text" })
But proved to not do much for me.
Seems like you forgot to prepend argument by $:
const fieldName = `key${argument}`;
await model.update({ [fieldName]: "completely new text" })

How to keep decreasing value in mongo until is 0

singleObj = await Objects.findByIdAndUpdate({ _id: req.body.id, }, { $inc: { 'total_obj': -1, 'total_stuff': 1 }, }, { new: true })
The user clicks a button and the value of 'total_obj' gets decreased by one. The value doesn't have to be less than 0.
I have tried to do this:
singleObj = await Objects.findByIdAndUpdate(
{ _id: req.body.id, "total_obj": { "$lt": 0 } },
{ "$set": { "total_obj": 0 } }
);
But this messes up every time I load the page and I have the values set to 0.
I also added on the definition on the schema:
total_obj: {
type: Number,
required: true,
min: 0
},
I assume you meant that you don't want your value to be lesser than 0.
You would need to use $gt operator and while you used $inc properly in the first findByIdAndUpdate you didn't use it in the second one.
Also, we are not looking only for id so we should use findOneAndUpdate instead.
singleObj = await Objects.findOneAndUpdate(
{ _id: req.body.id, "total_obj": { "$gt": 0 } },
{ $inc: { "total_obj": -1 } }
);
Try to fetch the Objects instance first and update the value only if > 0:
const singleObj = await Objects.findById(req.body.id)
if (!singleObj) // Error, obj not found
if (singleObj.total_obj > 0) {
singleObj.total_obj = singleObj.total_obj-1
await singleObj.save()
} else {
// `total_obj` is already zero
}

Mongoose - CastError Cast to string failed for value "Object"

I have Mongoose CastError issue. I made a nodeJs API. At the specific route, it returns data appended with some other data. I saw many fixes available here but my scenario is different.
Here is my model and the problem occurs at fields property.
const deviceSchema = new Schema({
device_id: { type: String, required: true },
user_id: { type: Schema.Types.ObjectId, ref: 'User', require: true },
location_latitude: { type: String, default: '0' },
location_longitude: { type: String, default: '0' },
fields: [{ type: String }],
field_id: { type: Schema.Types.ObjectId, ref: 'Field', required: true },
timestamp: {
type: Date,
default: Date.now,
},
});
and my controller is
exports.getAllDevices = async (req, res) => {
try {
let devices = await Device.find({})
.sort({
timestamp: 'desc',
})
.populate('user_id', ['name']);
// Let us get the last value of each field
for (let i = 0; i < devices.length; i++) {
for (let j = 0; j < devices[i].fields.length; j++) {
if (devices[i].fields[j] !== null && devices[i].fields[j] !== '') {
await influx
.query(
`select last(${devices[i].fields[j]}), ${devices[i].fields[j]} from mqtt_consumer where topic = '${devices[i].device_id}'`
)
.then((results) => {
************** Problem occurs here **************
if (results.length > 0) {
devices[i].fields[j] = {
name: devices[i].fields[j],
last: results[0].last,
};
} else {
devices[i].fields[j] = {
name: devices[i].fields[j],
last: 0,
};
}
************** Problem occurs here **************
});
}
}
}
// Return the results
res.status(200).json({
status: 'Success',
length: devices.length,
data: devices,
});
} catch (err) {
console.log(err);
res.status(500).json({
error: err,
});
}
};
It actually gets data from InfluxDB and appends it to fields property which was fetched from MongoDB as mentioned in my model. But it refused to append and CastError occurs.
After addition, it will look like this
I can't resolve this error after trying so many fixes. I don't know where I'm wrong. Please suggest to me some solution for this.
I can see you are not using devices variable as Mongoose Document. devices is an array of Documents.
I would like to suggest you to use lean() function to convert from Document to plain JavaScript object like
let devices = await Device.find({})
.sort({
timestamp: 'desc',
})
.populate('user_id', ['name'])
.lean();

How to access array elements that are defined in another array of Mongoose scheme object Array?

This is the User schema in mongoose:
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
name: {
type: String,
required: true,
},
Addtasks: [
{
topic: String,
words: Number,
keywords: String,
website: String,
otherdetails: String,
exampleRadios: String,
deadline: Date,
Date: String,
fileName: String,
Bigpaths: [],
},
],
});
module.exports = mongoose.model('User', userSchema);
I want to use/access the Bigpaths array, which is defined inside the Addtasks array, which is defined in User. Data is already are there in mongoDB, which I have inserted via UI page. I am trying the following code but I am getting this error in console:
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(
(element) => {
// ...
}
)
as
TypeError: Cannot read property 'Bigpaths' of undefined
at \Desktop\grumpytext\routes\index.js:99:71
Code:
const { files } = req;
User.findOne({ email: req.user.email }, function (error, data) {
if (error) {
console.log('Three');
} else if (data) {
if (Object.keys(data.Addtasks).length > 1) {
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(
(element) => {
files.forEach((currentElement) => {
if (element.name == currentElement.filename) {
files.pull(currentElement.filename);
}
});
}
);
}
}
});
How to resolve this error or how to access all the elements of Bigpaths array so that I can iterate it with forEach loop?
I'm not sure here, but I think you need to populate Addtasks prior to manipulating it:
const files = req.files;
User.findOne({email:req.user.email}).populate('Addtasks').exec((error, data) => {
if (error) {
console.log("Three");
}
else
{
if(data)
{
if(Object.keys(data.Addtasks).length > 1)
{
console.log("Addtasks count: " + Object.keys(data.Addtasks).length);
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(element => {
files.forEach(currentElement => {
if(element.name == currentElement.filename)
{
files.pull(currentElement.filename);
}
})
});
}
}
}
});
Please notice the log console.log("Addtasks count: " + Object.keys(data.Addtasks).length); - in case the solution does not work, I advise to add some prints, especially to check if the count of elements is as expected or properties within an object are fine.

GraphQL-js mutation optional arguments

how would I achieve a GraphQL Mutation in nodeJS that has arguments which are optional?
My current mutation has an args field, but all the arguments are mandatory. Since I couldn't find anything in the documentation, I don't know how or if this is possible.
This is my current code:
const fakeDB = {
count: 0
};
const schema = new GraphQLSchema({
query: //...
mutation: new GraphQLObjectType({
name: 'adsF',
fields: {
updateCount: {
type: GraphQLInt,
args: {
count: { type: GraphQLInt } // I want to make this argument optional
},
resolve: (value, { count }) => {
// Catch if count is null or undefined
if (count == null) {
// If so just update with default
fakeDB.count = 5;
} else {
fakeDB.count = count
}
return fakeDB.count;
})
}
}
})
});
Thanks for Your help!
Types in GraphQL are nullable by default. That means that the way you have specified the mutation at the moment makes the count optional. If you wanted a field to be mandatory you need to mark it as non null

Categories

Resources