Replace a nested object with another object - javascript

I want to replace a nested object with another object.
Is this the simplest way to express that?
r.expr({ foo: {bar: 1}, eck: true })
.merge({ foo: null }, { foo: {zim: 1} })
// Expected output: { foo: {zim: 1}, eck: true }

You can use r.literal for this: https://www.rethinkdb.com/api/javascript/literal
r.expr({ foo: {bar: 1}, eck: true })
.merge({ foo: r.literal({zim: 1}) })

Related

Is it possible to have optionally nested key-value pairs in TypeScript?

I would like to have an object like this:
const foo = { ... }; // how?
console.log(foo.a); // '1'
console.log(foo.a.bar); // { 'prop1': 1, 'prop2': 2 }
console.log(foo.b); // '2'
console.log(foo.b.bar); // { 'prop1': 1, 'prop2': 2 }
So, the default value of foo.a is described in the comment after the statement with the value '1'. But I would also like to go deeper into the object, to access a deeper property bar, of which a is the parent.
Something to demonstrate the desired structure:
const foo = {
a: '1',
[a.bar]: { prop1: 1, prop2: 2 },
b: '2',
[b.bar]: { prop1: 1, prop2: 2 }
}
Is this possible with TypeScript without using a function to call it? So something like this would not be a good solution for this case:
foo.a();
foo.a().bar();
Don't use this pattern.
Another version of what you seem to be asking is "Can I extend primitive types with additional properties"?
Is this possible?
Yes (sort of), but it's a code smell and I've never seen a compelling case for it. Here are two reasons why you shouldn't do it:
Anyone reviewing the code (even your future self) won't be expecting extra properties on these types, which will make it harder to read and understand.
Especially if the property names are going to be dynamic, there's a higher likelihood of overwriting/shadowing existing, standard property names on the object form of the primitive, which will almost certainly cause bugs.
With that out of the way — and, again, don't use this (you've been warned) — here's how you can do it:
References:
Object.assign()
String primitives and String objects
TS Playground
const bar = { prop1: 1, prop2: 2 };
const foo = {
a: Object.assign('one', { bar }),
b: Object.assign('two', { bar }),
};
/* The type of "foo" is:
{
a: "one" & {
bar: {
prop1: number;
prop2: number;
};
};
b: "two" & {
bar: {
prop1: number;
prop2: number;
};
};
}
*/
console.clear();
// This is a `String` (object), not a `string` (primitive):
console.log(foo.a); // String "one" { bar: { prop1: 1, prop2: 2 } }
// You can stringify it using any of these methods:
console.log(String(foo.a)); // "one"
console.log(foo.a.toString()); // "one"
console.log(`${foo.a}`); // "one"
console.log(foo.a.toUpperCase()); // "ONE"
console.log(foo.a.bar); // { prop1: 1, prop2: 2 }
console.log(foo.b); // String "two" { bar: { prop1: 1, prop2: 2 } }
console.log(String(foo.b)); // "two"
console.log(foo.b.toUpperCase()); // "TWO"
console.log(foo.b.bar); // { prop1: 1, prop2: 2 }
It would be better to devise a system for yourself of storing the value on a property on an object, (for example, as David suggested, using the value property).
Well, there's a possible solution but it's maybe not exactly what you want.
See when creating an object (for ex. a class), you have to possibility to give it a toString method. This way when the object is concatenated into a string. It executes your method instead. Here's an example:
const foo = {
a: {
prop1: 123,
prop2: 456,
toString(){
return "1" }
},
b: {
prop1: 123,
prop2: 456,
toString(){
return "1"
}
}
}
// The problem is that if you want to get the `"1"` of an object. You have to convert it into a string like for example :
console.log(`${foo.a}`)
console.log(foo.a.toString())
console.log("" + foo.a)
// And of course you can still access every possible property
console.log(foo.a.prop1)
console.log(foo.b.prop2)
console.log(foo.b.prop1 + ' - ' + foo.b)

Lodash deep pick

Hi I'm getting data from a soap service and transforming the xml to json and getting the value I need like this:
console.log(result['soap:Envelope']['soap:Body']['ns2:getFichaGeneralResponse']['return']['instituciones']['datosPrincipales']['registros'][1].valor)
is there any way to do something like this?
console.log(_.pick(result, 'registros'))
So I can get an object with the information I need?
If I understand you correctly, you have a complicated object and you want to pick some props by the specified path?
For example, you want to get { d: 'foo', e: 'bar' } by path a.b.c from the object below:
var object = {
a: {
b: {
c: {
d: 'foo',
e: 'bar',
f: 'baz'
}
}
},
g: {
h: 1
}
};
function pickPropsByPath(object, path, arrayOfPropsNames) {
return _.pick(_.get(object, path), arrayOfPropsNames);
}
console.log(pickPropsByPath(object, 'a.b.c', ['d', 'e'])) // => { d: 'foo', e: 'bar' }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

How to use include in Chai?

I'm trying to figure how can I pass an object and just check if the object is in the response using either that.includes or to.include from chai
I wrote a simple fiddle to check my problem:
https://jsfiddle.net/balexandre/4Loupnjk/2/
https://jsfiddle.net/balexandre/4Loupnjk/5/ with .deep flag
var e = {
"results": {
"total_rejected_recipients": 0,
"total_accepted_recipients": 1,
"id":"102618457586465882"
}
};
from my understanding, the e object should actually have the smaller object included... or am I missing something?
expect(e).to.include({
"results": {
"total_rejected_recipients": 0,
"total_accepted_recipients": 1
}
});
but I get the error:
assertionError: expected { Object (results) } to have property 'results' of { Object (total_rejected_recipients, total_accepted_recipients) }, but got { Object (total_rejected_recipients, total_accepted_recipients, ...) }
at Context.<anonymous> (:73:18)
First time on this framework though, might be the issue :)
First of all, you should use the deep.include assertion, as you have a deep object in there.
Anyways, it looks like this is a bug. The github ticket where this was implemented is located here and the relevant commit here.
The test coverage for this assertion is here:
expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}});
expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}, bar: {b: 2}});
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {a: 9}});
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {z: 1}});
expect({foo: obj1, bar: obj2}).to.not.deep.include({baz: {a: 1}});
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {a: 1}, bar: {b: 9}});
However, it breaks in the following scenario:
expect({ foo: obj1, bar: obj2 }).to.deep.include({ foo: { a: 1 }, bar: { } });
Better open the issue in chai repository, and temporary use the chai-subset package.

How to map an object by given key using lodash?

I have an object that looks something like this
{id: "2", name: "foo", price: "1"}
I want to transform this to the following
{2: {id: "2", name: "foo", price: "1"}}
I'm able to achieve this today if I wrap this object with a simple array like so thanks to the friendly keyBy method for array
_.keyBy([action.response], function(item) { return item.id; });
What I would prefer of course is the same result but without having to wrap this with an array first. Does transform/reduce or some other lodash v4 method provide this functionality?
Short solution based on ES6 computed property names: { [obj.id]: obj }
Example:
var obj = {id: "2", name: "foo", price: "1"}
var transformed = { [obj.id]: obj }
console.log(transformed)
You can do this directly with a function:
function convert(obj) {
var result = {}
result[obj.id] = obj
return result
}
Is that what you are looking for?

JavaScript recursive replace in Object

Folks, I have the following JSON object, in which I would like to recursively find every occurrence of foo with bar.
Also the [Object] can potentially contain foo which would also need to be replaced.
{ _id: 530797d8952e10129f97fde3,
Product: 'something',
Realm: [ 'something', 'something','foo' ],
Service: 'Node',
Owners: [ 'foo', 'something' ],
Project: 'something',
URLs:
[ { 'foo': [Object] },
{ 'foo': [Object] },
{ 'foo': [Object] } ] }
How would i loop through this? I've tried with but failed:
var cleanObject = {}
for (key in dirtyObject) {
key = key.replace('foo', 'bar');
cleanObject[key] = dirtyObject[key];
}
Tip: That's not a "JSON object". There is no such thing as a "JSON object". "JSON" is a string, representing an object. What you have there is an object literal.
However, JSON can help. Consider trying:
var cleanObject = JSON.parse(JSON.stringify(dirtyObject).replace(/foo/g,'bar'));

Categories