Find out if an object already exists in an array - javascript

I want to do a database operation only if my barcode is new to the structure.
My plan was either to use the function includes() or simply count the existence in the array.
I have found quite helpful code snippets like countDuplicate and the function include() to do the job but I guess my case is a little bit more specific.
But I not only have an object/array which consists of strings. (1st example)
I have an object which includes different objects and their properties.
//1st example (this works pretty well)
function countDuplicate(array, elem) { //just the special type of syntax for Vue/Node.js
return array.filter(item => item == elem).length;
}
var cars = ["Saab", "Volvo", "BMW", "BMW", "BMW"];
console.log(countDuplicate(cars, "BMW"); //will return 3
console.log(cars.includes("BMW")); //will return true
But as I said I have more a structure like that:
var object = {
sub_object1: { title: "test1", barcode: "0928546725" },
sub_object2: { title: "test2", barcode: "7340845435" },
};
How can I get the same results there?
My plan was to do it like that:
if(countDuplicate(object, "0928546725") == 0)
//... do my operations
But this not work because I don't really understand how I get into the structure of my objects. I experimented with different loops but nothing actually worked.
This is my array:
export default {
data() {
return {
form: {
items: [ //Barcodes
],
status: 1,
rent_time: Date.now()
},
submit: false,
empty: false,
}
},
____________________________________________________________________
Solutions:
I tried the following from #adiga and it works for the example but not for my real case.
This is a screen of my console:
So
A simple object.filter(a => a.barcode == elem) should work - #adiga
Like that?
countDuplicateBarcodes: function(obj, elem) {
//return Object.values(obj).filter(a => a.barcode == elem).length;
return obj.filter(a => a.barcode == elem).length;
}
Doesn't work anymore...

Get all the values of object in an array usingObject.values and then use filter
function countDuplicateBarcodes(obj, elem) {
return Object.values(obj).filter(a => a.barcode == elem).length;
}
const object = {
sub_object1: { title: "test1", barcode: "0928546725" },
sub_object2: { title: "test2", barcode: "7340845435" },
sub_object3: { title: "test3", barcode: "0928546725" }
};
console.log(countDuplicateBarcodes(object, "0928546725"))

If you just want to find a barcode in your object, then your question is a duplicate of for example
https://stackoverflow.com/a/46330189/295783
Changed to match you requirement:
const barcodes = {
sub_object1: { title: "test1", barcode: "0928546725" },
sub_object2: { title: "test2", barcode: "7340845435" },
};
const findMatch = (barcode, barcodes) => JSON.stringify(barcodes).includes(`"barcode":"${barcode}"`);
console.log(
findMatch("0928546725",barcodes)
)

Looking at your code, it appears like you actually use an array of objects and not a nested object. If that's the case, something like this should work:
let scannedTools = [
{barcode: "ABC", createdAt: "today"},
{barcode: "XYZ", createdAt: "123"}
];
function isAlreadyScanned(tool) {
return scannedTools.filter(t => t.barcode == tool.barcode ).length > 0
}
console.log(isAlreadyScanned({barcode: "ABC"}));
console.log(isAlreadyScanned({barcode: "ETRASDASD"}));
console.log(isAlreadyScanned({barcode: "XYZ"}));

Related

Return all values of nested arrays using string identifier

Given an object searchable, is there a simple way of returning all the id values using lodash or underscore.js (or equivalent) where I can define the path to id?
const searchable = {
things: [
{
id: 'thing-id-one',
properties: [
{ id: 'd1-i1' },
{ id: 'd1-i2' },
]
},
{
id: 'thing-id-two',
properties: [
{ id: 'd2-i1' },
{ id: 'd2-i2' },
]
}
]
}
I am looking to see if this is possible in a manner similar to how we can use lodash.get e.g. if we wanted to return the things array from searchable we could do
const things = _.get(searchable, 'things');
I can't seem to find anything similar in the documentation. I am looking for something
that could contain an implementation similar to:
_.<some_function>(searchable, 'things[].properties[].id')
Note: I am well aware of functions like Array.map etc and there are numerous ways of extracting the id property - it is this specific use case that I am trying to figure out, what library could support passing a path as a string like above or does lodash/underscore support such a method.
Found a solution using the package jsonpath
const jp = require('jsonpath');
const result = jp.query(searchable, '$.things[*].properties[*].id')
console.log(result);
// outputs: [ 'd1-i1', 'd1-i2', 'd2-i1', 'd2-i2' ]
you can do it easily in plain js
like this
const searchable = {
things: [
{
id: 'thing-id-one',
properties: [
{ id: 'd1-i1' },
{ id: 'd1-i2' },
]
},
{
id: 'thing-id-two',
properties: [
{ id: 'd2-i1' },
{ id: 'd2-i2' },
]
}
]
}
const search = (data, k) => {
if(typeof data !== 'object'){
return []
}
return Object.entries(data).flatMap(([key, value]) => key === k ? [value]: search(value, k))
}
console.log(search(searchable, 'id'))
_.map and _.flatten together with iteratee shorthands let you expand nested properties. Every time you need to expand into an array, just chain another map and flatten:
const searchable = {
things: [
{
id: 'thing-id-one',
properties: [
{ id: 'd1-i1' },
{ id: 'd1-i2' },
]
},
{
id: 'thing-id-two',
properties: [
{ id: 'd2-i1' },
{ id: 'd2-i2' },
]
}
]
}
// Let's say the path is "things[].properties[].id"
const result = _.chain(searchable)
.get('things').map('properties').flatten()
.map('id').value();
console.log(result);
<script src="https://cdn.jsdelivr.net/npm/underscore#1.13.4/underscore-umd-min.js"></script>

How do I populate an array of objects where every object has an array inside of it using response from rest API?

I can't google the right solution for this for about an hour straight,
So I'm getting a response from the API that looks like this:
[
{
"Name": "name1",
"Title": "Name One",
"Children": [
{
"Name": "Name 1.1",
"Title": "Name one point one"
},
]
And I need it to fit this kind of "mold" for the data to fit in:
{
title: 'Name One',
value: 'name1',
key: '1',
children: [
{
title: 'Name one point one',
value: 'Name 1.1',
key: 'key1',
},
I am trying to achieve this using a foreach but It's not working as intended because I need to do this all in one instance of a foreach.
Here's what I gave a go to(vue2):
created() {
getData().then(response => {
const formattedResponse = []
response.forEach((el, key) => {
formattedResponse.title = response.Title
formattedResponse.name = response.Name
formattedResponse.children = response.Children
})
})
Use map over the main array and use destructuring assignment to extract the properties by key, and relabel them, and then do exactly the same with the children array. Then return the updated array of objects.
const data=[{Name:"name1",Title:"Name One",Children:[{Name:"Name 1.1",Title:"Name one point one"}]},{Name:"name2",Title:"Name Two",Children:[{Name:"Name 1.2",Title:"Name one point two"}]}];
const result = data.map((obj, key) => {
const { Title: title, Name: value } = obj;
const children = obj.Children.map(obj => {
const { Title: title, Name: value } = obj;
return { title, value, key: (key + 1).toString() };
});
return { title, value, children };
});
console.log(result);
Your API response is JSON. All you need to do is:
var resp=JSON.parse(API response);

Best way to to pass the output of a function to child components in Vue

I have a parent component with a data object config as below:
data() {
return {
config: {
Groups: [
{
name: "A",
Types: [
{ mask: 1234, name: "Alice", type: 1},
{ mask: 5678, name "Bob", type: 1},
]
},
{
name: "B",
Types: [
{ mask: 9876, name: "Charlie", type: 2},
{ mask: 5432, name "Drake", type: 2},
]
}
],
},
Defaults: {
dummyBoolean: false,
dummyNumber: 1
}
}
}
}
There are also 2 child components that for each of them, I want to pass the Types array (within each elements of the Groups object) if each_element.name == child component's name.
What I've done so far is having a computed function for each of the components as follows (which is highly inefficient):
computed: {
dataSender_A() {
let array= []
this.config.Groups.forEach( element => {
if (element.name === "A") array = element.Types
});
return array
},
dataSender_B() {
let array= []
this.config.Groups.forEach( element => {
if (element.name === "B") array = element.Types
});
return array
},
}
I'm looking for a better alternative to make this happen (as I might have more child components) and two approaches I tried so far have failed.
Having only one computed function that takes the component's name as argument and can be passed like <child-component-A :types="dataSender('A')" /> <child-component-B :types="dataSender('B')" /> (As it throws error dataSender is not a function)
computed: {
dataSender: function(groupName) {
let array= []
this.config.Groups.forEach( element => {
if (element.name === groupName) array = element.Types
});
return array
},
}
Having the above function in methods and pass that as props to child components (As it passes the function itself, not the outputted array)
I'd appreciate any help on this.
The computed properties don't accept parameters that are involved in the calculation, In this case you could just use a method like :
methods: {
dataSender: function(groupName) {
let array= []
this.config.Groups.forEach( element => {
if (element.name === groupName) array = element.Types
});
return array
},
}

How to find the id of an object within an array having only one identified attribute of the "child" array

I would like help to develop a function using the most optimized approach in Javascript to find the id of the "parent" object having only a code of an "child" object (inside dataArray).
Example:
getIdParent("240#code") -> return "1"
[
{
id: 0,
dataArray:[
{
id: 182,
code: "182#code",
name: "Product1"
},
{
id: 183,
code: "183#code",
name: "Product2"
}
]
},
{
id: 1,
dataArray:[
{
id: 240,
code: "240#code",
name: "Product2"
},
{
id: 341,
code: "341#code",
name: "Product2"
}
]
}
]
Thanks in advance.
You don't really have a lot of options here.
The only real optimisation I can think of is based on how often you expect to call this function.
If it's only once, you just need to iterate the array, searching for values and return as early as possible to prevent unnecessary iterations.
function getIdParent(childCode) {
return arr.find(parent =>
parent.dataArray.some(({ code }) => code === childCode))?.id
}
If multiple times, you should build up an indexed map of child code to parent object and then reference that
const arr = [{"id":0,"dataArray":[{"id":182,"code":"182#code","name":"Product1"},{"id":183,"code":"183#code","name":"Product2"}]},{"id":1,"dataArray":[{"id":240,"code":"240#code","name":"Product2"},{"id":341,"code":"341#code","name":"Product2"}]}]
const codeMap = arr.reduceRight((map, parent) => {
parent.dataArray.forEach(({ code }) => {
map.set(code, parent)
})
return map
}, new Map())
function getIdParent(code) {
return codeMap.get(code)?.id
}
let search = ["240#code", "182#code", "NotFound"]
search.forEach(code => {
console.log("Parent ID for", code, "=", getIdParent(code))
})

How to filter JSON data by properties that contain certain strings?

I have a JSON Object that looks like this:
{
'name': 'Bob',
'friends': [
{
'name' : 'Ashley (Family)'
},
{
'name' : 'Steven (Non-Family)'
},
{
'name' : 'Chris (Family)'
}
]
}
How can I filter the above, so that it returns only the friends that are family? i.e. friends who's name contains '(Family)'?
function filterFriends (friends) {
return friends.filter(function(i) {
if (i.name.indexOf('(Family)') > -1) {
return i.name;
}
});
}
But the above doesn't seem to work... I don't know if I'm on the right track?
Other than a) using the phrase "JSON Object" which makes no sense and b) relying on sloppy automatic casting of booleans, you really don't have a problem. This "answer", with minor technical improvements will demonstrate that your code is just fine.
var data = {
name: 'Bob',
friends: [
{
name: 'Ashley (Family)'
},
{
name: 'Steven (Non-Family)'
},
{
name: 'Chris (Family)'
}
]
};
var family = data.friends.filter(f => f.name.indexOf('(Family)') > -1);
console.log(family);
// [{name: 'Ashley (Family)'}, {name: 'Chris (Family)'}]
If you want to write it into a function
function isFamily(name) {
return name.indexOf('(Family)') > -1;
}
function getFamily(friends) {
return friends.filter(f => isFamily(f.name));
}
var family = getFamily(data.friends);
ES5
var family = data.friends.filter(function(f) {
return f.name.indexOf('(Family)') > -1);
});
console.log(family);
Filter method should always return boolean value, this looks like returning always the string with the name.
Take a look to docs for .filter method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

Categories

Resources