pg-promise, using named parameters with nested objects - javascript

Is it possible to reference nested objects, when using named parameters with pg-promise, like the following example?
var obj = {
name: 'John',
address: {
postcode: 'abc'
}
};
db.query('SELECT * FROM users WHERE postcode=${address.postcode} AND name=${name}', obj);
At the moment the reference to the nested object is not resolved with the value, e.g. ${address.postcode} is left as is and not replaced with 'abc' in the query string.

NOTE: This answer is no longer valid since v6.10.0 of pg-promise, which started supporting Nested Named Parameters natively.
And the code example provided in the question will just work as is.
Only for pg-promise prior to v6.10.0
The library only formats Named Parameters, it doesn't evaluate them, therefore no, you cannot do it, at least not directly like that.
But you can make sub-properties available to the query-formatting engine through functions:
var obj = {
name: 'John',
address: {
postcode: 'abc'
},
addrCode: a => a.address.postcode // alias for accessing a sub-property
};
and then use WHERE postcode = ${addrCode}.
And the older / ES5 syntax, via this works also:
var obj = {
name: 'John',
address: {
postcode: 'abc'
},
addrCode: function(/*a*/) {
// a = this (can use both)
return this.address.postcode;
}
};
UPDATE
It is possible to make client-side evaluations work, but only with $1, $2, ... parameters:
db.query('... postcode = $1 AND name = $2', [obj.name, obj.address.postcode]);
NOTE: You cannot use evaluations like ${obj.address.postcode} directly inside the query string, because the value won't be correctly escaped.

Related

How to dynamically update an object field in JavaScript/TypeScript

I have a method for handling an update on this object. In this method I want to accept any field value that the object has, such as name, age, weight, eyeColor etc. If that field exists within that object, I'd like to be able to update the object dynamically for any field they pass in.
I am currently doing it incorrectly I believe with the spread operator while trying to update one field in the object. There is an error that fieldName does not exist within myObject. Does anyone know how to do this dynamically without need for a long switch statement checking each of the fields against fieldName passed in? In previous attempts tweaking with this I have successfully added a new field to the object named "fieldName" which is also not what I wanted.
If anyone has any ideas, that would be so helpful, thank you!
let myObject = {
name: 'John',
lastName: 'Smith',
age: 26,
weight: 200,
eyeColor: 'blue',
hairColor: 'blonde'
};
const handleUpdate = (fieldName: string, fieldValue: string | number) => {
if (fieldName in myObject) {
myObject = {...myObject, fieldName: fieldValue};
}
}
handleUpdate('name', 'Jack'); // Want this call to update the name of 'John' to 'Jack'
In short, you're looking for:
{...myObject, [fieldName]: fieldValue}
You can make a generalized, typesafe function to do this as follows:
function updateProp<TObj, K extends keyof TObj>(obj: TObj, key: K, value: TObj[K]) {
return {...obj, [key]: value};
}
and call it as follows:
const foo = { a: 1, b: "monkey" };
const updatedFoo = updateProp(foo, "b", "hello world")
Playground Link
You're looking for the Bracket notation property accessor:
myObject[fieldName] = fieldValue
Compared to the approach with the spread operator, this does actually update the object in place. I.e. if the reference in myObject was previously copied elsewhere, that reference will also "see" the updated field.
Whereas, by overriding the value with myObject = {...myObject}, you're creating a new object each time.

Javascript reference nested object elements from another module

Simple question, but it doesn't seem to be working how I expect...
I'm trying to access the value from a nested object, however I'm getting that (for this example) 'person' is not defined.
What am I doing wrong?
Example:
config.settings.js:
var configs = {
person: {
'name': 'John',
'number': 27,
'color': blue
},
place: {
'town': 'springville',
'population': 201827
}
}
module.exports = configs;
main.js:
var configSettings = require('config.settings');
module.exports = {
run: function(){
console.log(configSettings[person][name]);
}
}
You have to use dot accessor such as
configSettings.person.name
And make sure your are properly importing your config.
First make sure blue is defined otherwise is a typo and should be a string
person: {
'name': 'John',
'number': 27,
'color': "blue"
},
and I sugest use dot notation
configSettings.person.name
Had to make the inner keys strings and reference with configSettings.person['name']
Also I had to make the inner keys into strings- e.g. "person:", "place":
I'm just reporting what fixed it for me- I do not understand what the original problem was as of yet, without making the inner keys into strings I was getting type errors when trying to access.

Javascript object remove nesting

I am have an object that looks like this in the console,
res.local.details > Object {role-details : {} }
so to access this I would need to do res.local.details['role-details']
Is is possible to make it so I can "explode" role-details into details so I can just do
res.locals.details
to access the attributes from role-details
Yes, objects in JS are mutable. If you want to reassign data from one part of your object to another, you can just do it like this:
const myObj = {
name: {
first: 'John',
last: 'Smith',
},
address: {
streetNo: '123',
streetName: 'Main St',
city: {
name: 'Exampletown'
}
}
}
myObj.address.city.name // resolves to Exampletown
myObj.address.city = myObj.address.city.name
myObj.address.city /// resolves to Exampletown
This can be done in several ways.
In this particular case, where details just has that one property, you can just do:
res.local.details = res.local.details['role-details'];
In a more generic situation, details might have other properties that you don't want to destroy with this operation. In that case you can use:
Object.assign(res.local.details, res.local.details['role-details']);
With this, res.local.details will keep all its properties (provided they don't have the same name as properties of role-details), including role-details (but which becomes kind of obsolete).
The same can be achieved with:
res.local.details = {...res.local.details, ...res.local.details['role-details']};

Update dynamic object

I have an object :
{
...,
values: {},
...
}
values is empty by default.
Now I want to add dynamic object to this object :
[myDynamicProperty]: {
title: '...',
introduction: '...'
}
That's ok, I know how to do this. But, on other action, I have to add key: value or key: object to [myDynamicProperty], when I try something, I loose the values of my [myDynamicProperty]
I've tried to clone my initial object, but it doesn't work.
For sure, someone on stackoverflow has the solution.
You could take a two step approach by assigning a default object to myDynamicProperty and then assign the values to it.
This keeps all properties of object.values[myDynamicProperty] and changes only the given keys.
var object = {
values: {},
}
object.values[myDynamicProperty] = object.values[myDynamicProperty] || {};
Object.assign(object.values[myDynamicProperty], { title: '...', introduction: '...' });
If you are trying to convey that you are starting with an object such as:
var user = {
meta: {
first_name: "John",
last_name: "Smith"
}
}
and wish to add middle_name to the meta object property, then you should do the following.
Object.assign(user['meta'], {middle_name: "Harry"});
Note that the first object will be overwritten with values from the later object(s). The later object properties will take precedence over previous objects properties. See Mozilla for further details. WARNING: This is an ES6 feature, use a polyfill for backwards compatibility if necessary.

Array filteration and Extraction of data and append to new Array

I have an array with nested array
I want the data to append in a new array.
For the data extraction or filtration what method's i have to use, using library such as lodash
DATA
[
[
{
_id: 588d9b8a608f2a66c298849f,
email: 'sd#',
password: '$2a$10$6..L3c3tANi6ydt9gZbc1O6prPfUd3RB.ner5lilxRyEwo1lPsSoC',
isJobSeeker: true,
__v: 0,
lastName: 'shrestha',
firstName: 'manish',
isSeeker: true
}
],
[
{
_id: 588dbb4f7a48ce0d26cb99fd,
jobId: [Object],
seekerId: 588d9b8a608f2a66c298849f,
employerId: 588d7d6c0ec4512feb819825,
__v: 0,
}
]
]
REQUIRED DATA
[
{
_id: 588d9b8a608f2a66c298849f,
email: 'sd#',
password: '$2a$10$6..L3c3tANi6ydt9gZbc1O6prPfUd3RB.ner5lilxRyEwo1lPsSoC',
isJobSeeker: true,
__v: 0,
lastName: 'shrestha',
firstName: 'manish',
isSeeker: true
},
jobId: [{}, {}, {}] // ARRAY WITH OBJECTS
]
also i want to change the jobId key to other key of custom string as jobs
Following is my attempt:
console.log('Data filteration', data);
const filteredData = [];
filteredData.push(data[0][0]);
data[1].forEach((i) => {
filteredData[0].jobs = i.jobId
});
console.log('filteredData', filteredData);
First you should clean you data to have a better structure.
[
[
{ ... }
],
[
{ ... }
]
]
In this datastructure, its difficult to understand what does inner arrays signify. Instead you should use an object. That would define the purpose of array and make your code more readable.
var data=[[{_id:"588d9b8a608f2a66c298849f",email:"sd#",password:"$2a$10$6..L3c3tANi6ydt9gZbc1O6prPfUd3RB.ner5lilxRyEwo1lPsSoC",isJobSeeker:!0,__v:0,lastName:"shrestha",firstName:"manish",isSeeker:!0}],[{_id:"588dbb4f7a48ce0d26cb99fd",jobId:["test","test1"],seekerId:"588d9b8a608f2a66c298849f",employerId:"588d7d6c0ec4512feb819825",__v:0}]];
var cleanedData = {
userData: data[0],
userJobMap: data[1],
}
var result = cleanedData.userData.reduce(function(p,c){
if(c.isJobSeeker){
var job = cleanedData.userJobMap.filter(x=> x.seekerId === c._id);
// To copy object and not reference
var t = Object.assign({}, c, { jobId: job[0].jobId });
p.push(t)
}
return p
}, [])
console.log(result)
References
Array.map is a tool that iterates over all elements and return different value say a single property of return double value of all numbers in array. Note, this will yield an array of same size.
Array.filter on the other hand is use to filter array based on condition. This will return a subset of original data but elements will be same. You cannot change element structure.
Array.reduce is a tool that address cases where you need to return selected elements with parsed value. You can achieve same by chaining .filter().map() but then its an overkill as it would result in O(2n).
Object.assign In JS objects are passed by reference. So if you assign an object to a variable, you are not copying entire object, but only reference. So it you change anything in this variable, it will also reflect in original object. To avoid this, you need to copy value. This is where Object.assign comes. Note, its not supported by old browsers. For them you can check following post - What is the most efficient way to deep clone an object in JavaScript?
Note: All array functions are part of functional programming paradigm and are used to make your code more readable and concise but they come at an expense of performance. Traditional for will always perform faster then them. So if you want to focus on performance, always try to use for (though difference is very small but can add up for multiple cases and become substantial)

Categories

Resources