Related
I need to write a customizer for mergeWith. I've used defaultsDeep before and it worked exactly the way I want it to, except that defaultsDeep also merge nested arrays. I have 2 objects.
const baseObject = {
firstElement: { data: undefined },
secondElement: {
name: 'Canada',
items: [
{ city: 'Toronto', code: 12334},
{ city: 'Vancouver ', code: 33245}
]
}
};
const defaultObject = {
firstElement: { data: '13.01.2018'},
secondElement: {
name: 'Bresil',
items: [
{ city: 'Rio', code: 67584},
{ city: 'Manaus ', code: 90845},
{ city: 'Salvador ', code: 36745}
]
}
};
and when I do defaultsDeep(baseObject, defaultObject)
I get:
{
firstElement: { data: '13.01.2018' },
secondElement: {
name: 'Canada',
items: [
{city: 'Toronto', code: 12334},
{city: 'Vancouver ', code: 33245},
{city: 'Salvador ', code: 36745}]
}
};
with mergeWith(mergeWith(baseObject, defaultObject, (ObjValue) => ObjValue))
I get:
{
firstElement: { data: undefined },
secondElement: {
name: 'Canada',
items: [
{city: 'Toronto', code: 12334},
{city: 'Vancouver ', code: 33245}]
}
};
Please help me to write customizer for mergeWith, I would be very appreciated 🙂
I expect :
{
firstElement: { data: '13.01.2018' },
secondElement: {
name: 'Canada',
items: [
{city: 'Toronto', code: 12334},
{city: 'Vancouver ', code: 33245}]
}
}
I found some resolving, and I understand that some lines no have sens, but it's work somehow :
const customizer = (objValue, key) => {
if (isArray(key) || objValue?.subItems) return objValue;
if (key) return;
return objValue;
};
The customizer function of _.mergeWith() should return the value that you want or undefined, if you would like _.mergeWith() continue merging nested objects:
const { isArray, isObject, isUndefined, mergeWith } = _;
const customizer = (a, b) => {
if(isArray(a)) return a;
return isObject(a) || isUndefined(a) ? undefined : a;
}
const baseObject = {"firstElement":{},"secondElement":{"name":"Canada","items":[{"city":"Toronto","code":12334},{"city":"Vancouver ","code":33245}]}};
const defaultObject = {"firstElement":{"data":"13.01.2018"},"secondElement":{"name":"Bresil","items":[{"city":"Rio","code":67584},{"city":"Manaus ","code":90845},{"city":"Salvador ","code":36745}]}};
const result = mergeWith(baseObject, defaultObject, customizer);
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>
I've been trying to render my API response from Nodejs to display on my react table. I want to perform some calculations and filter out a few things on the response from the API response. But later while trying to display it on my tables, I'm having complications. I know its a pretty simple task but I'm unable to come up with the proper logic or approach for this. Thank you for helping out.
.then(response => {
console.log(response);
const result = response.data.rows;
setRes(result)
var arr = [];
Object.keys(result).forEach(function(key) {
arr.push(result[key]);
});
const filtered = {
Greeters:
{
nvCount: 0,
Taken: 0,
vCount: 0
},
Cleaning:{
nvCount: 0,
Taken: 0,
vCount: 0,
},
Intercession:{
nvCount: 0,
Taken: 0,
vCount: 0,
},
Media:{
nvCount: 0,
Taken: 0,
vCount: 0,
},
KidsChurch:{
nvCount: 0,
Taken: 0,
vCount: 0,
},
};
arr.map((el, i) => {
if (el.team.includes('Greeters')) {
if (el.preference.includes('NON-VEG')) {
filtered.Greeters.nvCount++;
}
else if (el.preference.includes('VEG')) {
filtered.Greeters.vCount++;
}
if (el.taken===true ) {
filtered.Greeters.Taken++;
}
}
else if (el.team.includes('Cleaning')) {
if (el.preference.includes('NON-VEG')) {
filtered.Cleaning.nvCount++;
}
else if (el.preference.includes('VEG')) {
filtered.Cleaning.vCount++;
}
if (el.taken===true ) {
filtered.Cleaning.Taken++;
}
}
else if (el.team.includes('Intercession')) {
if (el.preference.includes('NON-VEG')) {
filtered.Intercession.nvCount++;
}
else if (el.preference.includes('VEG')) {
filtered.Intercession.vCount++;
}
if (el.taken===true ) {
filtered.Intercession.Taken++;
}
}
else if (el.team.includes('Media')) {
if (el.preference.includes('NON-VEG')) {
filtered.Media.nvCount++;
}
else if (el.preference.includes('VEG')) {
filtered.Media.vCount++;
}
if (el.taken===true ) {
filtered.Media.Taken++;
}
}
else if (el.team.includes('Kids Church')) {
if (el.preference.includes('NON-VEG')) {
filtered.KidsChurch.nvCount++;
}
else if (el.preference.includes('VEG')) {
filtered.KidsChurch.vCount++;
}
if (el.taken===true ) {
filtered.KidsChurch.Taken++;
}
}
});
The response data from the API:
0
:
{id: '56', name: 'Prajwal V', phone: '990*******', preference: 'NON-VEG', team: 'Greeters', taken: false}
1
:
{id: '57', name: 'Amulya', phone: '63605******', preference: 'NON-VEG', team: 'Greeters', taken: true}
2
:
{id: '58', name: 'Devika', phone: '8618******', preference: 'NON-VEG', team: 'Greeters', taken: false}
3
:
{id: '59', name: 'Guru', phone: '9019*****', preference: 'NON-VEG', team: 'Greeters', taken: true}
4
:
{id: '60', name: 'Peter', phone: '9988*****', preference: 'VEG', team: 'Cleaning', taken: false}
I just want to find out the count("NON-VEG"), count("VEG"), and count(taken) for each team.
And I want to display these based on a SELECT dropdown that chooses the Team. eg: Select: 'Greeters', the count("NON-VEG"), count("VEG"), and count(taken) for 'Greeters' must be displayed in tabular format.
Current attempt,
<Select
className='SelectTeam'
closeMenuOnSelect={true}
components={animatedComponents}
isMulti={false}
options={teams}
name='team'
onChange={handleSelect}
/>
{res.map(el => {
return(
<div>
{team == el.team &&
<tr key={el.team}>
<td>{el.name}</td>
<td>{el.preference}</td>
</tr>
}
</div>
)
})
}
The data in the 'filtered' object has all the necessary data needed. In other words, I just need to display that filtered data based on the team selected or tell me a better approach to handle this complication
Thank you so much for helping out.
You can construct the filtered object dynamically like below code
let filtered = {};
teams.map(team=>{
filtered[team.name] = {
nvCount: 0,
Taken: 0,
vCount: 0,
};
});
result.map(user => {
if (user.preference.includes("NON-VEG")) {
filtered[user.team].nvCount += 1;
} else if (user.preference.includes('VEG')) {
filtered[user.team].vCount += 1;
}
if (user.taken === true) {
filtered[user.team].Taken += 1;
}
});
console.log(filtered);
setFilteredData(filtered);
Your filtered object would look like this,
{
"Greeters": {
"nvCount": 4,
"Taken": 2,
"vCount": 0
},
"Cleaning": {
"nvCount": 0,
"Taken": 0,
"vCount": 1
}
}
store it in filteredData state and display it
{selectedTeam && (
<>
<div>NV count: {filteredData[selectedTeam].nvCount}</div>
<div>Veg count: {filteredData[selectedTeam].vCount}</div>
<div>Taken: {filteredData[selectedTeam].Taken}</div>
</>
)}
selectedTeam is the selected data from your select box.
I tried callingsetFilter function on my Tabulator tree structure, in order to filter out items. It seems to only filter out top parents. Any idea how to make this work for any level (any children or parents)? http://tabulator.info/docs/4.1/tree doesn't say much about how filtering works.
Function
table.setFilter('id', '=', 214659) is not returning anything...
Tree structure
[
{
"level":0,
"name":"word1",
"id":125582,
"_children":[
{
"level":1,
"name":"word6",
"id":214659
},
{
"level":1,
"name":"word7",
"id":214633
},
{
"level":1,
"name":"word2",
"id":214263,
"_children":[
{
"level":2,
"name":"word8",
"id":131673
},
{
"level":2,
"name":"word9",
"id":125579
},
{
"level":2,
"name":"word10",
"id":125578
},
{
"level":2,
"name":"word4",
"id":172670,
"_children":[
{
"level":3,
"name":"word13",
"id":172669
},
{
"level":3,
"name":"word14",
"id":174777
},
{
"level":3,
"name":"word5",
"id":207661,
"_children":[
{
"level":4,
"name":"word15",
"id":216529
},
{
"level":4,
"name":"word16",
"id":223884,
"_children":[
{
"level":5,
"name":"word17",
"id":223885,
"_children":[
{
"level":6,
"name":"word18",
"id":229186,
"_children":[
{
"level":7,
"name":"word19",
"id":219062
},
{
"level":7,
"name":"word20",
"id":222243
}
]
}
]
}
]
}
]
}
]
},
{
"level":2,
"name":"word3",
"id":214266,
"_children":[
{
"level":3,
"name":"word11",
"id":216675
},
{
"level":3,
"name":"word12",
"id":216671
}
]
}
]
}
]
}
]
After a little searching found out an extension for lodash library called deepdash which has deep level filtering and it works quite well.
You will have 2 new dependencies but I think it will serve your purpose.
Check the documentation on how to install them here
In the snippet here you can see in the log the results. I made a sandbox also here
This is for a list of ids, one or more.
If you need only for one value change the conditional. return _.indexOf(idList, value.id) !== -1; to return id===value.id; where id is your id variable
Also after looking at the documentation from Tabulator, the have only one level filtering, even if you write your own custom filter it wouldn't help, because it expects a bool value to render the row or not. But only for the first level, so if the parent is not what you look for the child will be ignored. The only option for you is to filter the data outside the Tabulator.
const data = [
{
level: 0,
name: "word1",
id: 125582,
_children: [
{
level: 1,
name: "word6",
id: 214659
},
{
level: 1,
name: "word7",
id: 214633
},
{
level: 1,
name: "word2",
id: 214263,
_children: [
{
level: 2,
name: "word8",
id: 131673
},
{
level: 2,
name: "word9",
id: 125579
},
{
level: 2,
name: "word10",
id: 125578
},
{
level: 2,
name: "word4",
id: 172670,
_children: [
{
level: 3,
name: "word13",
id: 172669
},
{
level: 3,
name: "word14",
id: 174777
},
{
level: 3,
name: "word5",
id: 207661,
_children: [
{
level: 4,
name: "word15",
id: 216529
},
{
level: 4,
name: "word16",
id: 223884,
_children: [
{
level: 5,
name: "word17",
id: 223885,
_children: [
{
level: 6,
name: "word18",
id: 229186,
_children: [
{
level: 7,
name: "word19",
id: 219062
},
{
level: 7,
name: "word20",
id: 222243
}
]
}
]
}
]
}
]
}
]
},
{
level: 2,
name: "word3",
id: 214266,
_children: [
{
level: 3,
name: "word11",
id: 216675
},
{
level: 3,
name: "word12",
id: 216671
}
]
}
]
}
]
}
];
const idList = [214659];
const found = _.filterDeep(
data,
function(value) {
return _.indexOf(idList, value.id) !== -1;
},
{ tree: true, childrenPath: '_children' }
);
console.log(found);
<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.min.js"></script>
<script>
deepdash(_);
</script>
Here is a recursive function that will find the parent and/or children matching a condition.
In this example, the parent item will always be displayed if a child item is a match - even if the parent itself is not a match - but you can easily adjust the code to your needs by tuning the test in the for loop.
var filterTree = function (data, filter) {
if (data['_children'] && data['_children'].length > 0) {
for (var i in data['_children']) {
return data[filter.field] == filter.value || filterTree(data['_children'][i], filter);
}
}
return data[filter.field] == filter.value;
};
Call this function as a custom filter callback:
table.setFilter(filterTree, {field:'myfield', type:'=', value:'myvalue'});
Note that this is just example code that focuses on the logic of filtering a tree recursively. The above works only for the '=' comparison.
In a real situation, you will have to implement more code to handle all other operators supported by tabulator, as dynamic operator assignment is not possible in Javascript. You could maybe consider eval() but that's another story.
More info about dynamic operator assignment here:
Are Variable Operators Possible?
Here is an example of implementation handling all tabulator operators:
// Operators
var compare = {
'=': function(a, b) { return a == b },
'<': function(a, b) { return a < b },
'<=': function(a, b) { return a <= b },
'>': function(a, b) { return a > b },
'>=': function(a, b) { return a >= b },
'!=': function(a, b) { return a != b },
'like': function(a, b) { return a.includes(b)}
};
// Filter function
var filterTree = function (data, filter) {
if (data['_children'] && data['_children'].length > 0) {
for (var i in data['_children']) {
return compare[filter.type](data[filter.field], filter.value) || filterTree(data['_children'][i], filter);
}
}
return compare[filter.type](data[filter.field], filter.value);
};
// Set a filter. The operator can now be provided dynamically
table.setFilter(filterTree, {field:'myfield', type: '>=', value:'myvalue'});
I created a test Node.js script that uses Nano to generate some example data documents, create two views, and run two test queries. Each data document has two keys: "a" and "b". I'd like my query to result in all of the documents where "a" is between 1 and 3 and "b" is equal to 2. I tested a view/query pattern that I found online which uses a startkey array and an endkey array. However, it does not behave as expected when I constrain "a" before constraining "b", but it does appear to behave as expected when I constrain "b" before constraining "a".
Why does the b_then_a view appear to work but the a_then_b view does not? Is this approach incorrect? The script and its output are below.
var nano = require("nano")("http://HCOADAMM:HcoAdammRSM#localhost:5984");
let jasonDB = nano.db.use("jason");
const DESIGN_DOCUMENT_NAME = "findtest";
var testData = [
{ a: 1, b: 1 },
{ a: 1, b: 2 },
{ a: 1, b: 3 },
{ a: 1, b: 4 },
{ a: 2, b: 1 },
{ a: 2, b: 2 },
{ a: 2, b: 3 },
{ a: 2, b: 4 },
{ a: 3, b: 1 },
{ a: 3, b: 2 },
{ a: 3, b: 3 },
{ a: 3, b: 4 },
{ a: 4, b: 1 },
{ a: 4, b: 2 },
{ a: 4, b: 3 },
{ a: 4, b: 4 }
];
var shuffleArray = function(arrayIn) {
var arrayInLength = arrayIn.length;
var arrayOut = [];
while(arrayInLength)
arrayOut.push(arrayIn.splice(
parseInt(Math.random() * (arrayInLength--)), 1
)[0]);
return arrayOut;
}
var createTestRecords = function() {
var recordsShuffled = shuffleArray(testData);
recordsShuffled.forEach(function(record) {
jasonDB.insert(
record,
function(err, body) {
if(err)
console.log(err);
else
console.log("updated user doc " + JSON.stringify(body));
}
);
});
}
var createDesignDocument = function() {
jasonDB.get("_design/" + DESIGN_DOCUMENT_NAME, {}, function(err, body, headers) {
if(!err || err.error === "not_found") {
var dbObject = new Object();
dbObject._id = "_design/" + DESIGN_DOCUMENT_NAME;
if(!err) {
dbObject._rev = body._rev;
}
dbObject.language = "javascript";
dbObject.views = {
a_then_b: {
map: function(doc) {
emit([doc.a, doc.b]);
}
},
b_then_a: {
map: function(doc) {
emit([doc.b, doc.a]);
}
},
};
jasonDB.insert(dbObject, function(err, body, header) {
if(err) {
console.log("insert error:");
console.log(err);
} else {
console.log("created " + "jason/_design/" + DESIGN_DOCUMENT_NAME);
}
})
} else {
console.log("get error:");
console.log(err);
}
});
}
var queryTest = function() {
jasonDB.view(
DESIGN_DOCUMENT_NAME,
"a_then_b",
{ startkey: [1, 2], endkey: [3, 2] },
function(err, body) {
if(err) {
console.log(err);
} else {
console.log("a_then_b")
body.rows.forEach(function(el) {
console.log(el);
});
console.log("body.rows.length = " + body.rows.length);
console.log("");
}
}
);
jasonDB.view(
DESIGN_DOCUMENT_NAME,
"b_then_a",
{ startkey: [2, 1], endkey: [2, 3] },
function(err, body) {
if(err) {
console.log(err);
} else {
console.log("b_then_a")
body.rows.forEach(function(el) {
console.log(el);
});
console.log("body.rows.length = " + body.rows.length);
}
}
);
}
//createTestRecords();
//createDesignDocument();
setTimeout(function() {
queryTest();
}, 1000);
output:
a_then_b
{ id: '812f16b3826569ec94eb35d087030d64',
key: [ 1, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d087030709',
key: [ 1, 3 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702a846',
key: [ 1, 4 ],
value: null }
{ id: '812f16b3826569ec94eb35d087032077',
key: [ 2, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702fd89',
key: [ 2, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702caee',
key: [ 2, 3 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702c32a',
key: [ 2, 4 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702b358',
key: [ 3, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d087031386',
key: [ 3, 2 ],
value: null }
body.rows.length = 9
b_then_a
{ id: '812f16b3826569ec94eb35d087030d64',
key: [ 2, 1 ],
value: null }
{ id: '812f16b3826569ec94eb35d08702fd89',
key: [ 2, 2 ],
value: null }
{ id: '812f16b3826569ec94eb35d087031386',
key: [ 2, 3 ],
value: null }
body.rows.length = 3
You can only do this if the second key is the first in the index. So you need to revere the keys in your index, such that b is indexed first, and a, second. This will allow you to search for on a range of [2,1] through [2,3].
I am making a barcode scanner for my school project but i am stuck. I dont know how to scan through this object. I have this object with objects inside, and I need to scan through each object inside storage variable to check its barcode.
var storage = {
bolts: {
barcode: 57263144,
price: 0.5,
name: 'Plain Brackets',
stock: 25,
},
brackets: {
barcode: 13245627,
price: 0.2,
name: '100mm Bolts',
stock: 2,
},
}
I have a variable called barcode, and I need to test this variable if its the same like one of these. I tried using
for (var key in storage){
if (storage[key].barcode === barcode){
}
}
I would like the most simple way to do that.
Use Object.keys:
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
Below is the example:
var storage = {
"bolts": {
barcode: 57263144,
price: 0.5,
name: 'Plain Brackets',
stock: 25,
},
"brackets": {
barcode: 13245627,
price: 0.2,
name: '100mm Bolts',
stock: 2,
}
}
var barcode = 57263144;
Object.keys(storage).forEach(function(key) {
if(storage[key].barcode === barcode) { console.log("do something")}
});
A Fiddle:
https://jsfiddle.net/spechackers/34bhthza/
Use the recursive function to verify if exist more nodes in the objects, example:
const complexObj = {
name: "nobody",
address: { number: 22, moreNumbers: [1,2,3,4,5] },
colors: ["green", "red"],
numbersAgain: { first: 1, second: 4 }
};
function scanObj(obj){
for (let i in obj) {
/*
*Do some verificatio, example:
*I'd like to verify all numbers and if the numbers is greater than 3:
*/
if(typeof obj[i] == "number" && obj[i] > 3){ console.log(obj[i]); }
if (typeof obj[i] === "object") {
scanObj(obj[i])
}
}
}
//call the method
scanObj(complexObj);
Output: 22 4 5 4