Including isNil in lodash chain - javascript

I have a collection of entities like this:
var entities = [
{
location: null,
label: 'xyz'
},
{
location: {
city: 'city'
},
label: 'xyz'
}
{
label: 'xyz'
}
];
Trying to filter out entities with location = null, undefined or not existing at all. Using lodash.
When testing the location of the first entity in this way, it's returning the correct answer true:
_.isNil(_(entities[0]).get('location'));
but when I trying to include the isNil in chain, it returns Cannot read property 'valueOf' of null error:
_(entities[0]).get('location').isNil
Can isNil included somehow in the lodash chain?
here is the issue: https://codepen.io/neptune01/pen/qjxJwr
I'll need to use it somehow in this way:
_(entities).omitBy(_.get('location').isNil)
or
_(entities).omitBy(_(entity).get('location').isNil)

isNil() is not chainable.
See a complete list of non-chainable methods here.
You can use it like this, for your particular problem:
_.omitBy(entities, (el) => _.isNil(el.location))
var entities = [{
location: null,
label: 'xyz'
},
{
location: {
city: 'city'
},
label: 'xyz'
}
];
console.log(_.omitBy(entities, (el) => _.isNil(el.location)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Related

Mongodb find documents with given field value inside an array and its id in another array inside the same document

My data model:
{
_id: ObjectId,
persons:[{
_id: ObjectId,
name: String,
...
}],
relations: [{
type: String,
personId: ObjectId,
...
}],
...
}
Here's my issue:
I am trying to find documents where person's name is x and it's _id is inside the relations array (personId) with a given type.
Example:
My data:
[{
_id:"1",
persons:[{
_id:"1",
name: "Homer"
},
{
_id:"2",
name: "Bart"
}],
relations: [{
type:"House_Owner",
personId: 1,
}],
}]
Request_1:
Find all documents where "Homer" is the house owner
Result:
[{
_id:"1",
...
}]
Request_2:
Find all documents where "Bart" is the house owner
Result:
[]
Any help would be appreciated.
The only solution I see here is to do the find operation with the given name value and after that filter the mongodb result.
PS: I cannot change the existing data model
EDIT:
I found a solution to do this by using $where operator with a javascript function but I am not sure that's the most efficient way.
db.myCollection("x").find({
$where: function() {
for (const relation of this.relations) {
if(relation.type === "House_Owner") {
for (const person of this.persons) {
if(person.name === "Homer" && person._id.equals(relation.personId)) {
return true;
}
}
}
}
}
})
You can do something like this:
const requiredName="x"
const requiredId = "id"
await yourModel.find({$and:[{"relations.personId":requiredId },{"persons.name":requiredName}]})

Object with values as keys that store each individual object related to it using reduce: Javascript

just working through a problem and was wondering if anyone could shed some light on this issue I'm having. I'm supposed to take an array of objects (a set of parks) and I need to take a key from an object nested within it, use that as a new key and store an array of every object related by that same value we pulled for the key. Here's an example:
I'm working with data that looks a lot like this:
const myParks = [
{
name: "Garden of the Gods",
areaInSquareKm: 200,
location: {
state: "Colorado"
}
},
{
name: "Acadia",
areaInSquareKm: 198.6,
location: {
state: "Maine"
}
},
{
name: "Mountain Pass",
areaInSquareKm: 400.6,
location: {
state: "Colorado"
}
},
{
name: "Newleaf Forest",
areaInSquareKm: 150.4,
location: {
state: "Maine"
}
},
];
And I need to take the location.state value and use that as individual keys of a new object, then assign each key a value of the object with a related state. If the state is Maine, the key should contain the entire object with the related state:
{
"Maine": [
{
name: "Acadia",
areaInSquareKm: 198.6,
location: {
state: "Maine"
}
},
{
name: "Newleaf Forest",
areaInSquareKm: 150.4,
location: {
state: "Maine"
}
},
]
};
I was trying to do it like so:
function parkByState(parks) {
let stateParks = parks.reduce((result, park) => {
result[park.location.state] = parks.filter(park => { park.location.state })
}, {});
return stateParks
};
I can't for the life of me figure out how to do this properly. I can't change the structure, they MUST be assembled within an object, with the state names as keys, and have an array containing each individual park if the state matches the key. I just seriously don't know what I'm doing wrong. I keep getting an error:
Uncaught TypeError: Cannot set properties of undefined (setting 'Maine')
at <anonymous>:37:35
at Array.reduce (<anonymous>)
at parkByState (<anonymous>:36:26)
at <anonymous>:42:18
I'm relatively new to JavaScript and would love if anyone can shed some light on this. I needed to use the reduce() method to assemble the object. I figured using filter to filter the objects into each key would have made sense, but I can't seem to get the two methods to work together properly. You don't have to feed me the answer, but at the very least, please tell me what I'm doing wrong here. I've tried several different ways to do this and none seem to work. If I'm missing a key point of how to use these methods, please let me know what I can do to better understand what they are trying to do. I really appreciate all the help and I apologize if this is a dumb question. I'm just trying to understand how to reassemble an array of each park, stored in a key that is pulled from the state of each park. I'm sorry if the question isn't worded the absolute best, I really want to get better at this kind of stuff so I'm just trying to understand what I'm doing wrong here and how I can achieve the desired result.
Thank you in advance.
Without reduce we can do :
const myParks = [
{
name: "Garden of the Gods",
areaInSquareKm: 200,
location: {
state: "Colorado"
}
},
{
name: "Acadia",
areaInSquareKm: 198.6,
location: {
state: "Maine"
}
},
{
name: "Mountain Pass",
areaInSquareKm: 400.6,
location: {
state: "Colorado"
}
},
{
name: "Newleaf Forest",
areaInSquareKm: 150.4,
location: {
state: "Maine"
}
},
];
const stateNames = new Set(myParks.map(area => {
return area.location.state;
}));
const collectionsByStateName = {};
[...stateNames].forEach(stateName => {
collectionsByStateName[stateName] = [];
myParks.forEach(area => {
if(stateName === area.location.state) {
collectionsByStateName[stateName].push(area);
}
})
});
console.log(collectionsByStateName);
The callback that you pass to .reduce() should return a value. When you give an arrow funnction a body {} it must include return if you wish to return a value from it, otherwise, it will return undefined. Because you don't return anything from your reduce callback it currently returns undefined, so on the next iteration result will be undefined. This causes your error as you're trying to set a value of undefind which you can't do. Moreover, your .filter() needs to return a truthy value when you want to keep the value, and a falsy value when you want to discard it.
While you can do some modifications to your code to get the filter to work, I recommend not filtering at all. Instead, check what the current state is of the current park, and if that state is already in result, push to the existing array, otherwise, create a new key in result for that state with a new array holding the current state:
const myParks = [ { name: "Garden of the Gods", areaInSquareKm: 200, location: { state: "Colorado" } }, { name: "Acadia", areaInSquareKm: 198.6, location: { state: "Maine" } }, { name: "Mountain Pass", areaInSquareKm: 400.6, location: { state: "Colorado" } }, { name: "Newleaf Forest", areaInSquareKm: 150.4, location: { state: "Maine" } }, ];
function parkByState(parks) {
let stateParks = parks.reduce((result, park) => {
const key = park.location.state;
result[key] ??= []; // set `key` to an empty array if it doesn't exist, (similar to result[key] = result[key] || [];)
result[key].push(park);
return result;
}, {});
return stateParks;
};
console.log(parkByState(myParks));
As you said that you're new to JavaScript, I would do away with .reduce() here though. This particular example doesn't really need to use .reudce() and can be made more readable by using a for loop. I've also replace the nullish-coalescing operator with an if-statement which might ready more clearly if you're unfamiliar with ??
function parkByState(parks) {
const stateParks = {};
for(const park of parks) {
const key = park.location.state;
if(!stateParks[key])
stateParks[key] = [];
stateParks[key].push(park);
}
return stateParks;
}

How to get JSON keys and add extra fields?

I'm trying to get the key of these json objects in order to create a new object with extra filed to create table headers in a React app. JSON data:
let example = [
{
id: 1,
city: 'New York',
},
{
id: 2,
city: 'Paris',
},
]
The function:
getKeys() {
return example.map((key) => {
return {
cityName: key, // gets the whole array
capital: false,
};
});
}
I tries Object.keys( example);, it returns integers; 0, 1.
How can I get the keys in this case? Thanks.
You are trying to map the keys for an array since example is an array. If the data are consistent throughout the array get the first element example[0] and do Object.keys().
So Object.keys(example[0])
There's no need to get the keys if you just want to add a property to the items in the array. I think there's a misunderstanding about .map, which gives you a single item/object in the array, not the keys.
Something like this perhaps?
let example = [{
id: 1,
city: 'New York',
}, {
id: 2,
city: 'Paris',
}];
const modifiedArray = function(arr) {
return arr.map(item => {
return {
id: item.id,
cityName: item.city,
capital: false,
};
})
}
const newArray = modifiedArray (example);
console.log(newArray )

json object from javascript nested array

I'm using a nested array with the following structure:
arr[0]["id"] = "example0";
arr[0]["name"] = "name0";
arr[1]["id"] = "example1";
arr[1]["name"] = "name1";
arr[2]["id"] = "example2";
arr[2]["name"] = "name2";
now I'm trying to get a nested Json Object from this array
arr{
{
id: example0,
name: name00,
},
{
id: example1,
name: name01,
},
{
id: example2,
name: name02,
}
}
I tought it would work with JSON.stringify(arr); but it doesen't :(
I would be really happy for a solution.
Thank you!
If you are starting out with an array that looks like this, where each subarray's first element is the id and the second element is the name:
const array = [["example0", "name00"], ["example1", "name01"], ["example2", "name02"]]
You first need to map it to an array of Objects.
const arrayOfObjects = array.map((el) => ({
id: el[0],
name: el[1]
}))
Then you can call JSON.stringify(arrayOfObjects) to get the JSON.
You need to make a valid array:
arr = [
{
id: 'example0',
name: 'name00',
},
{
id: 'example1',
name: 'name01',
},
{
id: 'example2',
name: 'name02',
}
];
console.log(JSON.stringify(arr));
Note that I am assigning the array to a variable here. Also, I use [] to create an array where your original code had {}.

Nested Javascript Object : recursion and "complex" transformation (with lodash)

I apologize in advance for the complex example here; I tried to trim it down as much as I could to illustrate what I try to achieve
I have a complex structure that I need to traverse and transform based on some conditions; Here's an (short) example of the structure that should cover most scenarios:
{ PROP1: {
metadata: Object, // somewhere deeper in metadata I have a `value` key
parent: { $ref: String },
employee: {
parent: { $ref: String },
id: String,
metadata: Object,
products: {
metadata: Object,
model: { $ref: String },
type: 'array',
value: ["String", "String" , "String"] ,
[...]
},
model: {
id: String,
email: {
metadata: Object,
value: 'a#b.com',
type: 'string',
validity: Object,
[...]
},
name: {
firstName: {
metadata: Object,
value: 'John',
type: String,
validity: Object,
[...]
},
lastName: {
metadata: Object,
value: 'Smith',
type: String,
validity: Object,
[...]
},
}
},
operations: {
id: String,
items: [
{ action: {value: "UPDATE", model: {$ref: String }, [...] },
{...}
],
metadata: Object,
[...]
}
}
},
PROP2: {
// similar as PROP1
},
[... and so on ...]
}
I basically need to clean that up before sending it to the backend;
Whenever a value contains $ref, I don't want the key/val pair (e.g.: PROP1.parent is of no use and can be omitted)
whenever a value contains value, I need to omit everything else and move the value of value as the value of key (e.g.: PROP1.employee.products should equal ['String', 'String', 'String'])
keys like id, metadata, validity (etc) can be completely omitted regardless of its content
So the end result should be along those lines:
{ PROP1: {
employee: {
products: ['item','item','item'],
model: {
email: 'a#b.com',
name: { firstName: 'John', lastName: 'Smith'},
},
operations: [
{action: 'UPDATE'}
]
}
},
PROP2: { ... }
}
I tried lots of different approaches using different lodash methods but couldn't wrap my head around this...
Any help will be greatly appreciated
Thanks
In pseudo code, try something like this. Implement the specifics and post more info when you run into trouble.
var ignoreKeyArray = ["id", ...] // keys to ignore and remove
var newJSON = "{}";
for (property in JSON) {
var newProp = parseJSON(key, property);
insert newProp in newJSON object
}
var parseJSON = function (key, jsonBlob) {
if (key in ignoreKeyArray || jsonBlob contains value "$ref")
return "";
var jsonOut = key + ": {}";
for (child in jsonBlob) {
add parseJSON(child) to jsonOut;
}
return jsonOut;
}
If you have any questions, comment so I can extend the answer and clarify.

Categories

Resources