Loop and merge object in Lodash - arrays

I have a array of object, like this:
var obj = [{
employeeId: 1300000,
requestValue: 2
}, {
employeeId: 1300000,
requestValue: 3
}, {
employeeId: 1300001,
requestValue: 4
}]
I know how to do it in javascript. But, How can I a retrieve the following result using Lodash:
var result = {
1300000: [
{ requestValue: 2 },
{ requestValue: 3 }
],
1300001: [
{ requestValue: 4 }
]
}

Using Lodash:
Group By with employeeId
mapValues to map each group, and take only requestValue by using
map
Here is the example:
let input = [{"employeeId":1300000,"requestValue":2},{"employeeId":1300000,"requestValue":3},{"employeeId":1300001,"requestValue":4}],
res = _(input)
.groupBy('employeeId')
.mapValues(g => _.map(g, ({requestValue}) => ({requestValue})))
.value();
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Using Plain JavaScript
Take a hash (resulant) and start with iterating it using reduce
Check if the employee id exists as a key of the hash for each
employeeId, if exist use it otherwise create the key value pair with
a empty array
Take either the existing value (for the key) or the new one and push
requestValue
let input = [{"employeeId":1300000,"requestValue":2},{"employeeId":1300000,"requestValue":3},{"employeeId":1300001,"requestValue":4}],
res = input.reduce((r, {employeeId, requestValue})=> {
(r[employeeId] = r[employeeId] || []).push({requestValue});
return r;
}, {});
console.log(res);

Related

update object value in useState array nested

I have a nested value in array and I want to update value using useState and it is updated but it also create new index value in array which is not required.
let data = {
query: [
{
com: "",
id: 1,
rules: [{ fN: "tej", sN: "raj" }]
},
{}
]
};
here I want to update value of fN only but new index [1] created in query at same time. here is link to code - https://codesandbox.io/s/blissful-night-kkycxh?file=/src/App.js:103-239
I would do as below, using a state update function, as you are trying just with index 0 it doesn't really matter
useEffect(() => {
setQuery((prev)=>{
return prev.map((q,idx)=>{
if(idx === 0){
q.rules[0].fN = "ram"
}
return q
})
});
}, []);

Lodash Merge not updating object with correct values

I am trying to merge these two objects using Lodash merge.
Server object:
[
{
"id": "74738",
"customerId": "534430"
},
{
"id": "74742",
"customerId": "534429"
}
]
Local Object
[
{
"customerId": "534429"
"name": "ABC"
},
{
"customerId": "534430",
"name": "XYZ"
},
]
I am using lodash merge to combine these two objects based on attributes, I am using this code below:
merge({}, serverObject, localObject);
// Output: [{"id":"74738","customerId":"534429","name":"ABC"},{"id":"74742","customerId":"534430","name":"XYZ"}]
The object is not being updated based on the Customer Ids but instead by the sequence of local object.
Expected Output:
[{"id":"74738","customerId":"534430","name":"ABC"},{"id":"74742","customerId":"534429","name":"XYZ"}]
With lodash you can combine all arrays to a single one using _.flatten(), group by a predicate, and then map and merge each group to a single object.
Note: since your customerId is an integer, the items would be ordered by the numerical value.
const { map, groupBy, flatten, merge } = _
const fn = (predicate, ...arrs) => map(
groupBy(flatten(arrs), predicate),
group => merge({}, ...group)
)
const arr1 = [{"id":"74738","customerId":"534430"},{"id":"74742","customerId":"534429"}]
const arr2 = [{"customerId":"534429","name":"ABC"},{"customerId":"534430","name":"XYZ"}]
const result = fn('customerId', arr1, arr2)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
If you need to preserve the original order, flatten to a single array, and then reduce the items to a Map using the result of the predicate as the key. Merge each new item with the same key to the existing one in the Map. Convert the Map's values back to an array using Array.from():
const fn = (predicate, ...arrs) => Array.from(arrs
.flat()
.reduce((acc, o) => {
const key = predicate(o)
return acc.set(key, { ...acc.get(key), ...o })
}, new Map()).values()
)
const arr1 = [{"id":"74738","customerId":"534430"},{"id":"74742","customerId":"534429"}]
const arr2 = [{"customerId":"534429","name":"ABC"},{"customerId":"534430","name":"XYZ"}]
const result = fn(o => o.customerId, arr1, arr2)
console.log(result)

How to return objects that have matching value when comparing to a separate array

In my state I have an object called foodLog which holds all entries a user enters with one of the keys being foodSelectedKey and I'm trying to return all entries that have a matching value from that key with a different array called foodFilter.
However, this doesn't work and errors out saying foodLog.filter() isn't a function - I've looked this up and it's because it's an Object (I think). Any help would be greatly appreciated!
state = {
// log food is for the logged entries
foodLog: {},
// used for when filtering food entries
foodFilter: [],
};
findMatches = () => {
let foodLog = this.state.foodLog;
let foodFilter = this.state.foodFilter;
let matched = foodLog.filter((item) => {
return foodLog.foodsSelectedKey.map((food) => {
return foodFilter.includes(food);
});
});
};
I guess the reason behind the error Is not a function is that the object can not be looped. By that it means you can not iterate an object with differend variables inside, if it has no index to be iterated like an array. The same goes for map(), find() and similar functions which MUST be run with arrays - not objects.
As far as I understand you have an object named foodLog which has an array named foodsSelectedKey. We need to find intersected elements out of foodFilter with the array. This is what I came up with:
state = {
// log food is for the logged entries
foodLog: {
foodsSelectedKey: [
{ id: 1, name: "chicken" },
{ id: 2, name: "mashroom" }
]
},
// used for when filtering food entries
foodFilter: [
{ id: 1, name: "chicken" },
{ id: 2, name: "orange" }
]
};
findMatches = () => {
let foodLog = this.state.foodLog;
let foodFilter = this.state.foodFilter;
let matched = foodLog.foodsSelectedKey.filter((key) =>
{
for (let i=0; i<foodFilter.length;i++){
if(foodFilter[i].name===key.name)
return true
}
return false;
}
);
return matched;
};
The Output is filtered array, in this case, of one element only:
[{
id: 1
name: "chicken"
}]
In order to check the output - run console.log(findMatches()). Here is the CodeSandbox of the solution. (check console at right bottom)

Insert list data over the iteration(map)

Here I am trying to modify my data over the iteration and send some result to API call.
The API Call receives a request with a structured data format which is
{ list: [{ id: "1", name: "Hello" }, ... ] }
Somehow I managed to call the API with single data ( const params in my current code, it only accepts single data).
But now it has to be done with multiple data something like this:
{ list: [{ id: "1", name: "Hello" }, { id: "22", name: "Ed" }, { id: "36", name: "Jason" } ... ] }
Here is my current code
const [table, setTalbe] = useState(..); // assume, we have some table data here
const processNow = () => {
let id = 0;
let name = '';
// if table length is greater than 1, we go for the loop.
if (table.length >= 1) {
table.map(data => {
id = data.userId;
name = data.userName;
});
//insert table data to params, here I want to add whole table data into "list"
//the final result of this list should be something like this
//ex ) list: [{ id: '123', name: 'Josh' }, { id: '125', name: 'Sue' }, { id: '2222', name: 'Paker' } ...],
// but how??
const params: any = {
list: [
{
id: id,
name: name
},
],
};
//send PUT reqeust with params
axios
.put(
'/api/v1/tosent',
params,
)
.then(res => {
console.log('The response', res);
})
.catch(err => {
console.log('The error: ', err);
});
}
};
but I'm stuck with it, please help me to finish this code to work properly.
need your kind advice.
Array.prototype.map returns a new array with the function you pass applied to every element. You should study the MDN documentation on map to understand its use.
Your current code does nothing with the map return value:
table.map(data => {
id = data.userId;
name = data.userName;
});
You probably assumed .map would mutate the data, as in change it in place. Instead, the whole operation returns a new array.
It looks like you want to do:
const list = table.map(data => {
return {
id: data.userId,
name: data.userName
}
});
This is applying a function to every element in the array that will map each element to a new object, matching your question, with an id and name key. Then it looks like you want to pass the returned value of map (which we named list above) to your call:
const params: any = {
list: list
};

How to increase counter on repetition of value under an array mongodb

I have a mongoose schema like this:
{
"_id" : ObjectId("5a7acda13b808dbed05d6505"),
"symbol" : "#AKS",
"counter" : 4
},
{
"_id" : ObjectId("5a7acda13b808dbed05d6506"),
"symbol" : "#AKD",
"counter" : 5
}
Now if I want to update multiple column i.e "symbol" values on one query then MongoDB updateMany Query will do. This is Query:
MyCollectionName.updateMany({ 'symbol' : { $in : req.body.array}}, { $inc : { 'counter': 1 } }, function(err, data) {
if(err) {
console.log('error')
} else {
console.log('value incremented')
}
});
By this Query If I give the Array value i.e
var array = ["#AKS", "#AKD"];
Then it will Increment the counter of Both. My Question is If I will Provide the Same value on an array then I want Two increment not one. Like this:
var array = ["#AKS", "#AKS"];
//I want the Increment of 2.
var array = [#AKS", "#AKS", "#AKS", "#AKS"]
//at this stage I want the counter of Increment is 4
But currently it will do Only One. Is this possible????
Any help is really appreciated.
You can use the bulkWrite API for this update as it allows you to compose an array of bulkWrite() write operations in which you can use the updateOne operation for each element in the array. The following example shows how you can apply it in your case:
let ops = [];
const handleResult = res => console.log(res);
const handleError = err => console.error(err);
req.body.array.forEach(function(item) {
ops.push({
"updateOne": {
"filter": { "symbol": item },
"update": { "$inc": { "counter": 1 } }
}
});
if (ops.length === 1000) {
MyCollectionName.bulkWrite(ops).then(handleResult).catch(handleError);
ops = [];
}
})
if (ops.length > 0) MyCollectionName.bulkWrite(ops).then(handleResult).catch(handleError);
what if instead of using updateMany you just forEach your array:
const yourArray = req.body.array;
yourArray.forEach(function(item) {
MyCollectionName.update({ 'symbol': { $in: item }}, { $inc: { 'counter': 1 }, function (err, data) {
// additional code
});
});

Resources