Preventing duplicate objects from being added to array? - javascript

I am building a little shop for a client and storing the information as an array of objects. But I want to ensure that I am not creating "duplicate" objects. I have seen similar solutions, but perhaps it is my "newness" to coding preventing me from getting the gist of them to implement in my own code, so I'd like some advice specific to what I have done.
I have tried putting my code in an if look, and if no "part", my variable looking for part number, exists in the code, then add the part, and could not get it to function.
Here is the function I am working on:
function submitButton(something) {
window.scroll(0, 0);
cartData = ($(this).attr("data").split(','));
arrObj.push({
part: cartData[0],
description: cartData[1]
});
}
arrObj is defined as a global variable, and is what I am working with here, with a "part" and a "description", which is the data I am trying to save from elsewhere and output to my "#cart". I have that part working, I just want to ensure that the user cannot add the same item twice. (or more times.)
Sorry if my code is shoddy or I look ignorant; I am currently a student trying to figure these things out so most of JS and Jquery is completely new to me. Thank you.

You can create a proxy and use Map to hold and access values, something like this
let cart = new Map([{ id: 1, title: "Dog toy" }, { id: 2, title: "Best of Stackoverflow 2018" }].map(v=>[v.id,v]));
let handler = {
set: function(target,prop, value, reciver){
if(target.has(+prop)){
console.log('already available')
} else{
target.set(prop,value)
}
},
get: function(target,prop){
return target.get(prop)
}
}
let proxied = new Proxy(cart, handler)
proxied['1'] = {id:1,title:'Dog toy'}
proxied['3'] = {id:3,title:'Dog toy new value'}
console.log(proxied['3'])

Assuming the 'part' property is unique on every cartData, I did checking only based on it.
function submitButton(something) {
window.scroll(0, 0);
cartData = ($(this).attr("data").split(','));
if(!isDuplicate(cartData))
arrObj.push({
part: cartData[0],
description: cartData[1]
});
}
const isDuplicate = (arr) => {
for(obj of arrObj){
if(arr[0] === obj.part)
return true;
}
return false;
}
If you want to do the checking on both 'part' and 'description' properties, you may replace the if statement with if(arr[0] === obj.part && arr[1] === obj.description).

Thanks everyone for their suggestions. Using this and help from a friend, this is the solution that worked:
function submitButton(something) {
window.scroll(0,0);
cartData = ($(this).attr("data").split(','));
let cartObj = {
part: cartData[0],
description: cartData[1],
quantity: 1
}
match = false
arrObj.forEach(function(cartObject){
if (cartObject.part == cartData[0]) {
match = true;
}
})
console.log(arrObj);
if (!match) {
arrObj.push(cartObj);
}

Okay, you have multiple possible approaches to this. All of them need you to specify some kind of identifier on the items which the user can add. Usually, this is just an ID integer.
So, if you have that integer you can do the following check to make sure it's not in the array of objects:
let cart = [{ id: 1, title: "Dog toy" }, { id: 2, title: "Best of Stackoverflow 2018" }];
function isInCart(id) {
return cart.some(obj => obj.id === id);
}
console.log(isInCart(1));
console.log(isInCart(3));
Another approach is saving the items by their id in an object:
let cart = { 1: { title: "Dog toy" }, 2: { title: "Best of Stackoverflow 2018" } };
function isInCart(id) {
if(cart[id]) return true;
return false;
}

Try to use indexOf to check if the object exists, for example:
var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('aaa'));
// expected output: -1

Related

Updating Json Value with that of another Json

I want to update automatically the value of comments_list with the values in the comments JSON object
const tweet = JSON.stringify({"tweet_id":1,"created_at":"2022-06-28","comments_list":[]})
const comments = JSON.stringify({"tweet_id":1,"commenter_id": 2"commenter_first_name":"tito","commenter_username":"tito_lulu"})
The final output should look like this
{"tweet_id":1,"created_at":"2022-06-28","comments_list":[{"commenter_id": 2"commenter_first_name":"tito","commenter_username":"tito_lulu"}]}
I'd work with those strings in an object form, otherwise string-manipulation could be slow in some cases.
This is by no means the fastest solution but perhaps the idea behind it can be helpful.
const tweet = [{
"tweet_id": 1,
"created_at": "2022-06-28",
"comments_list": []
}]; // There could be many tweet objects so wrap it in an array
const comments = [{
"tweet_id": 1,
"commenter_id": 2,
"commenter_first_name": "tito",
"commenter_username": "tito_lulu"
},
{
"tweet_id": 1,
"commenter_id": 5,
"commenter_first_name": "me-too",
"commenter_username": "me294"
}
]; // Same here, could be many comments right?
let UpdatedTweets = [];
// There are faster ways to do this, but for your question
tweet.forEach((tweet, tweetIndex) => {
// Loop each tweet
let post = tweet;
comments.forEach((comment, commentIndex) => {
if (comment.tweet_id == tweet.tweet_id) {
// we have a match lets combine them
tweet.comments_list.push({
commenter_id: comment.comment_id,
commenter_first_name: comment.commenter_first_name,
commenter_username: comment.commenter_username
});
}
});
UpdatedTweets.push(post);
});
console.log(JSON.stringify(UpdatedTweets));
The general idea is:
Parse the JSON into JS objects
Update the target object with the complementary information
Stringify the target object into JSON (only if you need to, eg. send the data to some other machine)
In your case:
const tweet = JSON.stringify({"tweet_id":1,"created_at":"2022-06-28","comments_list":[]});
const comments = JSON.stringify({"tweet_id":1,"commenter_id": 2,
"commenter_first_name":"tito","commenter_username":"tito_lulu"});
let o_tweet = JSON.parse(tweet)
, o_comments = JSON.parse(comments)
;
if (Array.isArray(comments)) { // Test whether that is a single or multiple comments
comments.forEach( c => { o_tweet.comments_list.push(c); });
} else {
o_tweet.comments_list.push(o_comments);
}
console.log(o_tweet);
// Only if needed:
// let newtweet = JSON.stringify(o_tweet)

How can I access multiply nested sub objects in javascript?

I have a larger code which handles and sorts data. In it I want to work with objects to keep it easier and better structured. I have multiple categories and all of them have different nested subobjects, which I have trouble accessing writing/reading.
I searched on the web, w3schools but couldn't find my mistake, so sry for this entry level question!
I wrote a test function to better understand objects!
function test(){
var report, time, name, date, value;
report = 'Income Statement';
time = 'Annually';
name = 'Revenue';
date = '2017';
value = '10000000';
data = {}
data[report] = {}
data[report][time] = {}
data[report][time][name] = {}
data[report][time][name][date] = value;
console.log(data);
}
As to my understanding what this code does is:
-create an empty object data
-create an empty subobject report
-create an empty subsubobject time
-create an empty subsubsubobject name
-gives the subsubsubobject name a key/value pair date:value
(at least that was my intention to do)
First I tried to skip creating empty objects and directly fill data{} with:
data = {}
data[report][time][name][date] = value; but he seems to cannot set properties to this.
So I created like above coded first empty subobjects for all subcategories, is this really necessary or am I falling for a simple syntax mistake?
However he still doesn't log me the desired output which would be:
{ 'Income Statement': { Annually: { Revenue: {2017:10000000} } } }
and instead gives me:
{ 'Income Statement': { Annually: { Revenue: [Object] } } }
Simply put.. what am I doing wrong? :D
Thanks in advance for any kind of help!
Best regards
I don't think you are doing anything wrong. I pasted same code in JS console and it is giving proper result.
Screenshot of console with result of function
Different ways to initialize object
Static Data
let data = {
'Income Statement': {
'Annually': {
'Revenue': {
'2017': '10000000'
}
}
}
}
document.querySelector("#data-result").innerHTML = JSON.stringify(data)
<div id="data-result"></div>
Dynamic Data
var report, time, name, date, value;
report = 'Income Statement';
time = 'Annually';
name = 'Revenue';
date = '2017';
value = '10000000';
let data = {
[report]: {
[time]: {
[name]: {
[date]: value
}
}
}
}
document.querySelector("#object-result").innerHTML = JSON.stringify(data)
<div id="object-result"></div>
You can also consider different ways to store same data.
Example -
let data = [{
report: 'Income Statement'
time: 'Annually'
name: 'Revenue'
date: '2017'
value: '10000000'
}]
So now, if you want data by date in future you can get that by using filter
let data_2017 = data.filter(x => x.date === '2017');
It is correct !! I received { Income Statement: { Annually: { Revenue: {2017:10000000} } } } at console as an output with your given code.
Are u trying to save that data in some variable using test() ??
If yes then you need to use return data at the end of the definition on the function test instead of consol.log(data).

Use variable to store "change.doc" path

I'm trying to use variable as a firestore doc path :
console.log(change.doc.data().m_1.name); <----- This work well !
a = 1;
let me = change.doc.data().m_+a; <----- But not that....
console.log(me.name);
How can i do that ?
Thank you in advance ! :)
You should use brackets when using dynamic property.
let me = change.doc.data()['m_' + a];
I think you want to build the name of the key as its own variable and use that to index into the object.
const a = 1;
const key = "m_" + a;
const me = change.doc.data()[key];
When you use your a variable in your example you're asking JS to add the number 1 to your functions output. This is not the correct way. You want to use a key to access the data from your data() functions return output as shown below.
change = {
doc: {
data: function() {
return {
m_1: {
name: "Mario",
occupation: "plumber",
siblings: 1,
age: 24
},
m_2: {
name: "Mike",
occupation: "developer",
siblings: 3,
age: "28"
}
}
}
}
}
console.log("Old way:" + change.doc.data().m_1.name);
const a = 1;
let me = change.doc.data()['m_' + a];
console.log("Desired way: " + me.name)
I have assumed a simple data structure derived from your question but I am not certain that it's what you get. But it might look a little like it.
EDIT awww.... The page didn't refresh and I did not see the two first answers :( well... at least we agree

Functions Invoking other Functions exercise I'm stumped on

First-time poster here and have run into a speed bump in my pre-work for a 6-month full-stack boot camp I'm enrolled in for November.
I'm working on some exercises on repl.it and this one is on javascript functions. You're told to write 3 functions called mealMaker, slice, and cook.
You're given an empty array and are told to fill it with objects like so:
const arrayOfFoodObjects = [
{
"food": "beef",
"type": "meat"
},
{
"food": "zucchini",
"type": "vegetable"
},
{
"food": "bacon",
"type": "meat"
},
{
"food": "okra",
"type": "vegetable"
}
];
They want you to have the cook function take all the objects that have "type": "meat" and return a string that says "Cooked ("food": value)" (e.g. "Cooked beef") and similarly with the slice function for "type": "vegetable" they want "("food": value) slices" (e.g. "Okra slices").
Then the mealMaker function takes what those functions spit out and creates an array as such: ["Cooked beef", "Okra slices" ...].
Where I'm stuck is I wrote a .filter() function that just returns a filtered array of those objects which I soon realized wouldn't serve its purpose. I guess I'm trying to figure out how to write a function so I can filter the meat and vegetables separately and then have them spit out the required string.
What's confusing me is how to target the "food" value and plug it into a certain string after filtering with the "type" value.
This is the rest of the code I have written so far which may or may not help.
var redMeat = arrayOfFoodObjects.filter(function(cook) {
return cook.type == "meat";
});
var veggies = arrayOfFoodObjects.filter(function(slice) {
return slice.type == "vegetable";
});
console.log(veggies, redMeat)
With the console just looking like:
[ { food: 'zucchini', type: 'vegetable' },
{ food: 'okra', type: 'vegetable' } ] [ { food: 'beef', type: 'meat' },
{ food: 'bacon', type: 'meat' } ]
I'm probably not tackling this the right way as I've spent a good amount of time trying different things I had found on Google and applying them as best I could but this was the closest I managed to get. Any help is greatly appreciated, thanks.
PS I'm not super familiar with this format of a function as I came up with this through some searches on Google. If someone wouldn't mind explaining how this may differ from the function format I'm used to seeing, that'd be awesome. I'm not sure about which part of it is the "name" of the function. The functions I've worked with so far typically look like:
function nameOfFunction(value(s)) {
*action*;
}
You are not doing what they ask.
They want a cook function and a slice function:
function cook(arr){
//for each element of the array, return its mapped value (they ask a string)
return arr.map( function(foodObject){
return `Cooked ${foodObject.food}`
})
}
function slice(arr){
//do it
}
let cooks = cook(arrayOfFoodObjects)
let slices = slice(arrayOfFoodObjects)
then feed what the function spit out to mealMaker (as instructed):
function mealMaker(cooks, slices){
return cooks.map( function(cook, idxCook){
let slice = slices[idxCook];
//guess what to do with cook and slice
})
}
mealMaker(cooks, slices)
I think something alone these lines is requested:
const cook = product => "cooked " + product.food;
const slice = product => product.food + " slices";
const mealMaker = (products) => {
const meatProducts = products.filter(product => product.type === "meat");
const veggieProducts = products.filter(product => product.type === "vegetable");
return [
...cook(meatProducts),
...slice(veggieProducts)
];
}
mealMaker(arrayOfFoodObjects);
Notice the fat arrow syntax for writing functions. How it is different compared to regular functions, is explained here on Mozilla.
Welcome holdenprkr!
I think you are on the right track! For now, we have a way to get an array of veggies and another one for meats:
var redMeat = arrayOfFoodObjects.filter(function(cook) {
return cook.type == "meat";
});
var veggies = arrayOfFoodObjects.filter(function(slice) {
return slice.type == "vegetable";
});
So far so good, now we want a cook function that takes our readMeat array, and converts it to a array of strings. So, something in the lines of:
function cook(readMeatsArray) {
// convert readMeatsArray to cookedMeatsArray
// [{'food': 'beef', 'type': 'meat'}, ...]
// to
// ['Cooked beef', ...]
}
And then a slice function for the veggies:
function slice(veggiesArray) {
// convert veggiesArray to slicedVeggiesArray
// [{'food': 'okra', 'type': 'vegetable'}, ...]
// to
// ['Okra slices', ...]
}
So, if we combine this in an mealMaker function we now have:
function mealMaker() {
// First we get our arrays
var redMeat = arrayOfFoodObjects.filter(function(cook) {
return cook.type == "meat";
});
var veggies = arrayOfFoodObjects.filter(function(slice) {
return slice.type == "vegetable";
});
// Then we convert our object arrays to string arrays
var cookedMeats = cook(redMeat);
var slicedVeggies = slice(veggies);
// Now we combine the resulting arrays and return it
var mealArray = cookedMeats.concat(slicedVeggies);
return mealArray;
}
This would be one approach, hope it helps.
PD: I left the functions cook and slice empty on purpose, you can get some inspiration from user753642's answer ;)

Get filtered elements from an Object

I want to get the value associated with the condition "Color" defined in var A.
I'm getting the keys of the object, but I want to get the value associated with the condition "Color"
function TestOBJ(){
var A = [
[['apple'],'red'],
[['tomatoes','strawberry'],'red'],
[['sky', 'deep sea'],'blue'],
[['frog'],'green']
]
var dataOBJ={};
for(var j=0;j<A.length;j++){
dataOBJ[j]= {
CONTENT: A[j][0],
COR: A[j][1]
}
}
Logger.log(dataOBJ);
const filtered = Object.keys(dataOBJ)
.filter(function esSuficientementeGrande(elemento) {
//Logger.log(dataOBJ[elemento].CONTENT[0]);
if( dataOBJ[elemento].COR == 'red'){
Logger.log(dataOBJ[elemento].CONTENT);
return JSON.stringify(dataOBJ[elemento]);
}
});
Logger.log(filtered);
}
For example:
I expect the results:
apple
tomatoes, strawberry
You want to retrieve the values by the condition of the color.
For example, when you give red as the condition, you want to retrieve apple tomatoes, strawberry.
In this case, I thought that you might need "apple", "tomatoes", "strawberry".
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this modification? Please think of this as just one of several answers.
Modified script 1:
If your script is modified, how about this modification?
function TestOBJ(){
var A = [
[['apple'],'red'],
[['tomatoes','strawberry'],'red'],
[['sky', 'deep sea'],'blue'],
[['frog'],'green']
]
var dataOBJ={};
for(var j=0;j<A.length;j++){
dataOBJ[j]= {
CONTENT: A[j][0],
COR: A[j][1]
}
}
Logger.log(dataOBJ);
const filtered = Object.keys(dataOBJ)
.reduce(function(ar, elemento) {
if (dataOBJ[elemento].COR == 'red') ar = ar.concat(dataOBJ[elemento].CONTENT);
return ar;
}, []);
Logger.log(filtered);
}
Modified script 2:
As other pattern, how about this?
function TestOBJ(){
var A = [
[['apple'],'red'],
[['tomatoes','strawberry'],'red'],
[['sky', 'deep sea'],'blue'],
[['frog'],'green']
]
// I modified below script.
var color = "red";
var res = A.reduce(function(ar, e) {
if (e[1] === color) ar = ar.concat(e[0]);
return ar;
}, []);
Logger.log(res);
}
Result:
["apple","tomatoes","strawberry"]
Reference:
reduce()
If I misunderstood your question and this was not the result you want, I apologize.

Categories

Resources