Firestore bulk add field to array - javascript

I am struggling to add a field to an map in an array. I am trying to add "canAssist": false to each map in the array for each of the countries.
Here is my database:
[
{
"Afghanistan": {
"country": "Afghanistan",
"countryCode": "AF",
"countryCodeAlt": "AFG",
"emoji": "🇦🇫",
"packages": [
{
"name": "Luxury Couple",
"cost": "$2000.00",
// I want to add canAssist:false here!
},
{
"name": "Quick Retreat",
"cost": "$1000.00",
// I want to add canAssist:false here!
}
]
}
},
{...}
{...}
]
This is what I've tried:
let travelData = database.collection('countries').doc(docName);
travelData.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(array) {
packages.map(package => {
return package.add({
canAssist: false
});
})
});
});

You can use Object.values() and object destructuring to achieve this.
const querySnapshot = [
{
Afghanistan: {
country: 'Afghanistan',
countryCode: 'AF',
countryCodeAlt: 'AFG',
emoji: '🇦🇫',
packages: [
{
name: 'Luxury Couple',
cost: '$2000.00',
// I want to add canAssist:false here!
},
{
name: 'Quick Retreat',
cost: '$1000.00',
// I want to add canAssist:false here!
},
],
},
},
{
...
},
{
...
},
];
const updateSnapshot = (snapshot, newData) => {
return snapshot.map(countryData => {
// only one field with the name of the country
const country = Object.values(countryData)[0];
let updatedCountry = { ...country };
const field = country[newData.field];
if (field) {
if (typeof field === 'string') {
updatedCountry[newData.field] = newData.values;
} else if (Array.isArray(field)) {
updatedCountry[newData.field] = field.map(data => ({ ...data, ...newData.values }));
}
}
return { [updatedCountry.country]: updatedCountry };
});
};
(() => {
console.log('Original', JSON.stringify(querySnapshot, null, 4));
const updatedSnapshot = updateSnapshot(querySnapshot, { field: 'packages', values: { canAssist: false } });
console.log('Updated', JSON.stringify(updatedSnapshot, null, 4));
const updatedSnapshot2 = updateSnapshot(querySnapshot, { field: 'emoji', values: '🇪🇸' });
console.log('Spanish!', JSON.stringify(updatedSnapshot2, null, 4));
})();
Of course, you don't need to have that dynamism with the 'newData', I just added in case you want to play around any field of your datasource.

Related

How to return array of objects by comparing two arrays javascript

i have two arrays Here, alreadyAddedAreas is single Array and areasData is a nested Array- Here areasData look like this.Here what i want to return data Like in same structure as Areas Data and add isAdded property if its present in alreadyAddedAreas
const areasData=[
countries: [
{
id: 123,
cities:[
{
id: 001,
areas: [{
id: 890,
}, {
id:891
}]
},
{
id: 002,
areas: [{
id: 897,
}, {
id:899
}]
},
]
}
]
]
//alreadyAddedAreas is an Array of Added Areas
const areas: [{
id: 890,
}, {
id:891
}]
// Here what i want to return data Like in same structure as Areas Data and add isAdded property if its present in alreadyAddedAreas
export const getFilteredAreasList1 = (areasData, alreadyAddedAreas) => {
const filteredArray = [];
if (areasData && alreadyAddedAreas) {
areasData[0]?.cities?.map((city) => {
return city?.areas?.map((area) => {
if (
!alreadyAddedAreas.find((item) => item?.areaID?._id === area?._id)
) {
filteredArray.push({
...area,
isAdded: false,
});
} else {
filteredArray.push({
...area,
isAdded: true,
});
}
});
});
return filteredArray;
}
};

How to check if a value in an array is present in other object and accordingly return a new object

I have an array
const dataCheck = ["Rohit","Ravi"];
I have another array of object
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
I want to check if any value in dataCheck is present in the userData and then return a new array with the below data
const newData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit", status: "present" },
{ name: "Ravi", status: "present" },
];
I tried to do something using loops but not getting the expected results
const dataCheck = ["Rohit", "Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" }
];
let newDataValue = {};
let newData = [];
userData.forEach((user) => {
const name = user.name;
dataCheck.forEach((userName) => {
if (name === userName) {
newDataValue = {
name: name,
status: "present"
};
} else {
newDataValue = {
name: name
};
}
newData.push(newDataValue);
});
});
console.log(newData);
My trial gives me repeated results multiple results which is just duplicates
You should use map() and a Set.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const set = new Set(dataCheck);
const output = userData.map(data => set.has(data.name) ? ({...data, status: "present"}): data)
console.log(output)
.as-console-wrapper { max-height: 100% !important; top: 0; }
A Set allows for lookups in O(1) time and therefore this algorithm works in O(n) time. If you would use the array for lookups (e.g. using indcludes(), find() etc.) the runtime would be O(n²). Although this will certainly not matter at all for such small arrays, it will become more relevant the larger the array gets.
map() is used here because you want a 1:1 mapping of inputs to outputs. The only thing to determine then is, what the output should be. It is either the input, if the value is not in the Set, or it is the input extended by one property status set to "present". You can check for the presence in a Set using the has() method and can use the ternary operator ? to make the decision which case it is.
const dataCheck = ["Rohit", "Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
// map through every object and check if name property
// exists in data check with help of filter.
// if it exists the length of filter should be 1 so
// you should return { name: el.name, status: "present" } else
// return { name: el.name }
let newData = userData.map((el) => {
if (dataCheck.filter((name) => name === el.name).length > 0) {
return { name: el.name, status: "present" };
} else {
return { name: el.name };
}
});
console.log("newdata: ", newData);
A better approach would be to use map over userData array, find for matching element in dataCheck, if found return matching element + a status key or just return the found element as it is.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const getUpdatedObject = () => {
return userData.map(userData => {
const userDetail = dataCheck.find(data => userData.name === data);
if(userDetail) return {userDetail, status:"present"}
else return {...userData}
});
}
console.log(getUpdatedObject())
Working fiddle
Loop through userData, check if name is includes in dataCheck. If true add status 'present'.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
for (let user of userData) {
if(dataCheck.includes(user.name)) {
user.status = 'present'
}
}
console.log(userData)
You are seeing repeated results due to the second loop dataCheck.forEach((userName) => { as every loop of dataCheck will fire the if/else statement and add something to the final array. However many values you add to dataCheck will be however many duplicates you get.
Only need to loop through one array and check if the value is in the other array so no duplicates get added.
const dataCheck = ["Rohit", "Ravi"];
const userData = [{ name: "Sagar" }, { name: "Vishal" }, { name: "Rohit" }, { name: "Ravi" }];
let newDataValue = {};
let newData = [];
// loop thru the users
userData.forEach((user) => {
// set the user
const name = user.name;
// check if in array
if (dataCheck.indexOf(name) >= 0) {
newDataValue = {
name: name,
status: "present",
};
}
// not in array
else {
newDataValue = {
name: name,
};
}
newData.push(newDataValue);
});
console.log(newData);
So you will do like this :
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const newUserData = userData.map( user => {
dataCheck.forEach( data => {
if( data === user.name )
user.status = "present";
});
return user;
} );
console.log( newUserData );

Update nested array ES6, JavaScript

I have the following array of objects:
[{
idChatPublic: "1",
message: "hello",
chatLike: [{
id: "1",
idChatPublic: "1"
}]
}]
What I want is simply add a new object into chatLike array.
Here is my attempt, but it doesn't seem to be working whats wrong with this piece of code?
async function sendLike(messageId: string) {
const newLike = {
idChatPublic: messageId,
}
mutateMessages(
(data) => {
console.log(data) // returns the array I want to update
data.map((message) => {
if (message.idChatPublic === messageId) {
console.log(message.chatLike) // returns the array inside the object I want to update
return {
...message,
chatLike: [...message.chatLike, newLike]
}
} else {
return message
}
})
}
)
}
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Probably, you have to create const with new array and return it:
const newData = data.map((message) => {
if (message.idChatPublic === messageId) {
console.log(message.chatLike) // returns the array inside the object I want to update
return {
...message,
chatLike: [...message.chatLike, newLike]
}
} else {
return message
}
});
return newData;
const data = [
{
idChatPublic: "1",
message: "hello",
chatLike: [
{
id: "1",
idChatPublic: "1",
},
],
},
];
function updateChatLike() {
return data.map((d) => {
return {
...d,
chatLike: [
...d.chatLike,
{
id: 2,
idChatPublic: "2",
},
],
};
});
}
console.log(JSON.stringify(updateChatLike(), null, 4));
I have used JSON.stringify() to log complete nested object
Output
[
{
"idChatPublic": "1",
"message": "hello",
"chatLike": [
{
"id": "1",
"idChatPublic": "1"
},
{
"id": 2,
"idChatPublic": "2"
}
]
}
]
You don't need map(). I think you can do that like this:
async function sendLike(messageId: string) {
const newLike = {
idChatPublic: messageId,
};
mutateMessages((data) => {
data.forEach((message) => {
if (message.idChatPublic === messageId) {
message.chatLike.push(newLike);
}
}
});
}
Loop throw your objects array with forEach() and if the id will match you can update chatLike array with push() to add a new newLike object.
Map is not necessary here in your case.
Try this.
const data = [{
idChatPublic: "1",
message: "hello",
chatLike: [{
id: "1",
idChatPublic: "1"
}]
}];
console.log("before " , data);
sendLike(1);
console.log("after " , data);
function sendLike(messageId) {
const newLike = {
idChatPublic: messageId,
}
// mutateMessages((data) => {
data.forEach((message) => {
//console.log(message.idChatPublic);
if (message.idChatPublic == messageId) {
message.chatLike.push(newLike);
}
});
//});
}

Tying to change key values inside an object but its adding double values

Tying to change key values inside an object but its adding double values or its adding all values at once. Every name must get an value which in this case is a language slug. Not sure what I am doing wrong.
// the data
const routesObj = [
{ name: 'dashboard.index' },
{ name: 'settings.index' },
{ name: 'settings.general' },
{ ... }
]
// end results (how i want it to be)
[
{
nl: {
routes: [
{
name: 'nl.dashboard.index'
},
{
name: 'nl.dashboard.index'
},
{
name: 'nl.settings.general'
}
]
}
},
{
en: {
routes: [
{
name: 'en.dashboard.index'
},
{
name: 'en.dashboard.index'
},
{
name: 'en.settings.general'
}
]
}
}
]
// how its working now(not good)
[
{
nl: {
routes: [
{
name: 'en.nl.dashboard.index'//adding both languages
},
...
]
}
},
...
]
const routeBuilder = (routes, languages) => {
let newRoutes = []
languages.forEach(function(lang){
Object.keys(routes).forEach(function(key){
routes[key]['name'] = lang+'.'+routes[key]['name']
});
newRoutes[lang] = {routes};
});
return newRoutes
}
routeBuilder(routesObj, ['nl','en'])
The problem is here:
Object.keys(routes).forEach(function(key){
routes[key]['name'] = lang+'.'+routes[key]['name']
});
newRoutes[lang] = {routes};
routes is a reference to routesObj, so the code above modifies the original object in each languages.forEach iteration. The solution is to clone routes so that each iteration has a unique copy.
newRoutes is an array, but it's being used like an object in newRoutes[lang]. To insert an object into the newRoutes array, use Array.prototype.push.
const routesObj = [
{ name: 'dashboard.index' },
{ name: 'settings.index' },
{ name: 'settings.general' },
]
const routeBuilder = (routes, languages) => {
const newRoutes = []
languages.forEach(function(lang) {
routes = routesObj.map(x => ({...x})); // 1️⃣
Object.keys(routes).forEach(function(key){
routes[key]['name'] = lang+'.'+routes[key]['name']
});
newRoutes.push({ [lang]: { routes } }); // 2️⃣
})
return newRoutes;
}
const routes = routeBuilder(routesObj, ['nl','en'])
console.log(routes)
Alternatively, use nested Array.prototoype.maps:
const routesObj = [
{ name: 'dashboard.index' },
{ name: 'settings.index' },
{ name: 'settings.general' },
]
const routeBuilder = (routes, languages) => {
return languages.map(lang => {
return {
[lang]: {
routes: routes.map(route => ({ ...route, name: lang + '.' + route.name })),
}
}
})
}
const routes = routeBuilder(routesObj, ['nl','en'])
console.log(routes)

Cant access data inside nested array of objects

I have an array of objects that I want to iterate over and create a new array of objects.
First I map over the data, then I loop through each object to extract the values. I want to store the Location name and value from each object.
My code is returning null results. I can't change the way data is declared. Can someone help me understand why I keep getting null results?
[
{
"euValue": null,
"asValue": null
}
]
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
let formattedData = [];
let euValue, asValue;
formattedData = data.map(location => {
for (const l in location) {
if (location.hasOwnProperty(l)) {
const _this = location[l];
euValue = _this.Location === "Europe" ? _this.Value : null;
asValue = _this.Location === "Asia" ? _this.Value : null;
}
}
return {
euValue,
asValue
};
});
return formattedData;
};
const newData = formatData();
console.log(newData);
Edit
Expected result is
[
{
"euValue": “Ireland”,
"asValue": “China”
}
]
Assuming that inside data you could have multiple objects with a Location array that have only 2 objects (one for Europe and another one for Asia) you should change your function to something like this
const data = [
{
Locations: [
{
Location: { Name: "Europe" },
Value: "Ireland"
},
{
Location: { Name: "Asia" },
Value: "China"
}
]
}
];
const formatData = () => {
// iterate all data objects
return data.map((topLocation) => {
const res = {};
// loop over Location children objects
topLocation.Locations.forEach((location) => {
const { Name } = location.Location;
// decide where to save Value base on the Location.name
if (Name === "Europe") {
res.euValue = location.Value;
} else if (Name === "Asia") {
res.asValue = location.Value;
}
});
return res;
});
};
const newData = formatData();
console.log(newData);
you missing a second loop also you overwriting the usValue and euValue and you better use forEach instead of map in this case.
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = (data) => {
let formattedData = [],
values = {};
data.forEach(location => {
for (const l in location) {
if (location.hasOwnProperty(l)) {
const _this = location[l];
_this.forEach(el => {
if (el.Location.Name === "Europe") {
values["euValue"] = el.Value || null
}
if (el.Location.Name === "Asia") {
values["asValue"] = el.Value || null
}
})
}
}
});
formattedData.push(values)
return formattedData;
};
console.log(formatData(data))
I don't know what do you want to get from your code but this code may help you.
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
let formattedData = [];
formattedData = data.map(location => {
let euValue = [],
asValue = [];
for (const l in location.Locations) {
if (location.Locations.hasOwnProperty(l)) {
const _this = location.Locations[l];
if (_this.Location.Name === "Europe")
euValue.push(_this.Value);
else if (_this.Location.Name === "Asia")
asValue.push(_this.Value);
}
}
return {
euValue,
asValue
};
});
return formattedData;
};
const newData = formatData();
console.log(newData);
I'm sure many of the other answers are fine but the way I did it was to do the classic for loop to iterate over the data. I would have liked to have kept your ternary operators but I think you may need the if/else syntax.
var data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
let formattedData = [];
let euValue, asValue;
formattedData = data.map(location => {
for (const l in location) {
if (location.hasOwnProperty(l)) {
const _this = location[l];
for (let i = 0; i < _this.length; i++) {
if (_this[i].Location.Name === "Europe") {
euValue = _this[i].Value;
} else if (_this[i].Location.Name === "Asia") {
asValue = _this[i].Value;
} else {
euValue, asValue = null;
}
}
}
}
return {
euValue,
asValue
};
});
return formattedData;
};
const newData = formatData();
console.log(newData);
Using Array.prototype.flatMap() might help you get the array you desire in a cleaner way:
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
const formattedData = data.flatMap(item => {
const object = {}
item.Locations.map(location => {
const continent = location.Location.Name
let country = {}
if (continent === 'Europe') country = {
euValue: location.Value
}
if (continent === 'Asia') country = {
asValue: location.Value
}
Object.assign(object, country)
});
return object
});
return formattedData;
}
const newData = formatData();
console.log(newData);

Categories