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" })
Related
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();
I'm trying to send an object from front to back.
this is my function :
export const addComponent = (newComponent, inputFields) => (dispatch) => {
const url = process.env.REACT_APP_ADD_COMPONENT;
var componentBody = {
type: newComponent.type,
name: newComponent.name,
};
var componentTest = inputFields.map((inputField) => {
return Object.defineProperty(componentBody, inputField.property, {
value: inputField.content,
});
});
console.log(componentTest);
axios
.put(url, componentTest)
.then(dispatch({ type: ADD_COMPONENT, payload: componentTest }))
.catch((err) => {
console.log("Add failed", err);
});
};
When I log componentTest, it get the strucutre that I want, which mean :
{
description: "je décris",
environnement: "j'environne",
name: "test",
type: "Données"
}
But on the backside, in my route when I log req.body, there is only type and name which are present. Like if the defineProperty function doesn't records my object...
I presume that i need to enumerate all the properties of my object, but my knowledges stop here
I founded it,
If someone else need it.
With defineProperty you need to configure your new object by adding :
var componentTest = inputFields.map((inputField) => {
return Object.defineProperty(componentBody, inputField.property, {
value: inputField.content,
writable: true,
enumerable: true,
configurable: true,
});
});
Now i can see my object fully.
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.
I have an array of objects like this:
const data = [{
_id:"49847444033",
name:"yoko"
},{
_id:"49847433333",
name:"doira"
}]
I have to change each item name property to something like this :
...
{
_id:"49847433333",
name:{
en:"John"
}
}
My attempt is to loop object like following :
data.forEach((item) => {
item.name = {en:"john"}
console.log(item)
})
But this always console the original item and the name property value is not modified.
const newData = data.map(user => ({ _id: user._id, name: { en: user.name } }))
I created a library to express transformations like this very simply.
const { pipe, fork, get } = require('rubico')
const data =
[ { _id: '49847444033', name: 'yoko'}
, { _id: '49847433333', name: 'doira'}
]
const onData = pipe([
fork({
_id: get('_id'), // data => data._id
name: fork({ en: get('name') }), // data => ({ en: data.name })
}),
console.log,
])
data.map(onData) /*
{ _id: '49847444033', name: { en: 'yoko' } }
{ _id: '49847433333', name: { en: 'doira' } }
*/
I've commented the code above, but to really understand rubico and get started using it, I recommend you read the intuition and then the docs
try somthing like:
const newList = data.map(obj => {
return { _id: obj._id, name: { en: obj.name } }
});
and the newList list is your new data list so you can do it:
data = newList;
EDIT:
if you have more properties you can change the return line to:
return { ...obj, name: { en: obj.name } }
what will happen here, it will deploy all the object properties as they are, and modify the name property, unfortunately, every property you want to modify, you have to re-write it.
What is the workaround to update the dataLine when using data.Items.map()
I am getting eslint error:
Assignment to property of function parameter 'dataLine'
You can see I am deleting Other property and modifying dataLine.Config
const data = {
Type: "API",
Items: [{
State: [{Name: "Pending"}],
Config: {
Size: "M"
},
Other: "string.."
}]
}
const newItems = data.Items.map(({State,...dataLine}) => {
if (data.Type == "API") {
dataLine.Config = {
Size: "L"
};
delete dataLine.Other;
}
return dataLine;
});
console.log(JSON.stringify(newItems, null, 2));
About eslint, I think it's a missing piece, because if you write your function in an equivalent way:
data.Items.map((dataLine) => {
if (data.Type == "API") {
dataLine.Config = {
Size: "L"
};
delete dataLine.Other;
}
return dataLine;
});
you won't receive any warning. Maybe it's the case of open an issue there.
You could pass {props : true}, like GProst said, but this will enforce you to not make the assignment of any property of the parameter, which is a good thing, for example:
const newItems = data.Items.map(({State,...dataLine}) => {
if (data.Type == "API") {
dataLine.Config = { // not allowed with props : true
Size: "L"
};
delete dataLine.Other; // not allowed with props : true
}
return dataLine;
});
Why eslint have such a rule?
You are modifying the properties of data.Items, this will cause side effects on the external environment of the callback function on map. In some cases this will put you in bad situation, like not knowing which piece of code removed some property.
A suggestion about how you can deal with this safely is return an entire new object to make your data.Items immutable in your case:
const data = {
Type: "API",
Items: [{
State: [{Name: "Pending"}],
Config: {
Size: "M"
},
Other: "string.."
}]
}
const newItems = data.Items.map(({State,...dataLine}) => {
const dataLineCopy = JSON.parse(JSON.stringify(dataLine))
if (data.Type == "API") {
dataLineCopy.Config = {
Size: "L"
};
delete dataLineCopy.Other;
}
return dataLineCopy;
});
console.log(JSON.stringify(newItems, null, 2));
Edit no-param-reassign rule in eslint config, set option props to false:
"no-param-reassign": ["error", { "props": false }]