How to access specific items in array? [nodejs] - node.js

I'm having trouble getting specific items in this array.
[
{
"averages":[
{
"STATUS":"0",
"TYPE":"AAA",
},
{
"STATUS":"0",
"TYPE":"ABC",
},
{
"STATUS":"1",
"TYPE":"ESD",
},
{
"STATUS":"1",
"TYPE":"AAA",
},
]
},
{
"averages":[
{
"STATUS":"0",
"TYPE":"CCC",
},
{
"STATUS":"0",
"TYPE":"AAA",
},
{
"STATUS":"1",
"TYPE":"ESD",
},
{
"STATUS":"1",
"TYPE":"XXX",
},
]
},
{
"averages":[
{
"STATUS":"1",
"TIPO":"XXX",
},
{
"STATUS":"1",
"TYPE":"LLL",
},
{
"STATUS":"1",
"TYPE":"AAA",
},
{
"STATUS":"1",
"TYPE":"NU",
},
{
"STATUS":"0",
"TYPE":"XXX",
},
{
"STATUS":"1",
"TYPE":"AAA",
}
]
},
]
I'm trying to separate status from type AAA
[0, 1, 0, 1, 1, 1]
I get the array like this:
var quality = solicitacoes[0].produtor.dados[0].apiLaticinio[0].qualidade[0]
var qualityjson = JSON.parse(quality)
console.log(JSON.stringify(qualityjson));
I tried to use this material, but without success: enter link description here
What nodejs resource can I access the items in the way I mentioned?
Thanks if anyone can help me!
UPDATE:
I used this method to try to solve my problem.
function getStatus(arr) {
let results = [];
arr.forEach(avg => {
avg.averages.forEach(element => {
if (element["TYPE"] === 'AAA') {
results.push(element["STATUS"])
}
})
})
return results;
}
const results = getStatus(quality)
But I'm getting the following result:
TypeError: arr.forEach is not a function

To get all the status from the given array you can just use Array.map() inside Array.map() like below:
const getItems = (array = items) => {
return array.map((arItem, _) => {
return arItem.averages.map((nestItem, _) => {
return nestItem.STATUS
})
})
}
console.log([].concat(...getItems()))
//Output:
//[
// '0', '0', '1', '1',
// '0', '0', '1', '1',
// '1', '1', '1', '1',
// '0', '1'
//]
However if you are trying to get the items with TYPE='AAA', then you can use the following code:
const getTypeAAAItems = (array = items) => {
return array.map((arItem, _) => {
return arItem.averages.filter((nestItem) => {
return nestItem.TYPE === 'AAA'
})
})
}
//Output:
//[
// { STATUS: '0', TYPE: 'AAA' },
// { STATUS: '1', TYPE: 'AAA' },
// { STATUS: '0', TYPE: 'AAA' },
// { STATUS: '1', TYPE: 'AAA' },
// { STATUS: '1', TYPE: 'AAA' }
//]

I believe you're saying that you want to turn an array of objects with a STATUS field into an array of numbers. Let's say you have a single item from your above array:
{
"averages":[
{
"STATUS":"0",
"TYPE":"AAA",
},
{
"STATUS":"0",
"TYPE":"ABC",
},
{
"STATUS":"1",
"TYPE":"ESD",
},
{
"STATUS":"1",
"TYPE":"AAA",
},
]
},
Assuming the above is parsed and stored as item:
const statuses = item.averages.map(i => i.STATUS);
Array.prototype.map will let you manipulate each element of an array in the same way and return the new array (which will have the same number of elements as the old one).
In this case, we take an object with a STATUS and TYPE field, and instead return only the value of the STATUS field. So we end up with an array of numbers; [0, 0, 1, 1].

Related

count nested array inside documen using updateOne() function

const reset_qr_list_and_update_count = await stock_read_log.updateOne(
{
payload: {$ne:req.body.payload},
"qr_list.payload": req.body.new_qr_list[indexx].payload,
company_id:req.body.company_id
},
{
"$pull": {
"qr_list": {
payload: req.body.new_qr_list[indexx].payload
}
},
$set:{
qty: xx
},
}
);
$set:{
qty: model.aggreation({
//the query
}).count()
},
after pulling one of the list above,i want to re-count list left ,how can i achieve that within this function?

How to filter children in tree structure in Tabulator?

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'});

How to calculate based on the result of an aggregation?

For example, I can get the result of the average counts of request to a specific url base on parent id with the code below:
client.search({
index: 'console-*',
body: {
query: {
bool: {
query_string: {
query: 'meta.http.url:"https://www.google.com"'
}
}
},
aggs: {
parent_id: {
terms: {
field: 'parent_id'
}
}
}
},
size: 0
}).then(res => {
console.log(res.hits.total/res.aggregations.total.value)
})
Now let's say I have a number of urls like:
https://www.google.com
https://www.bing.com
https://www.apple.com
And I can use:
client.search({
index: 'console-*',
body: {
sort: {
'#timestamp': {
order: 'asc'
}
},
query: {
bool: {
must: [{
range: {
'#timestamp': {
gte: 'now-5m',
lte: 'now'
}
}
}, {
query_string: { query: '_exists_:meta.http.url' }
}]
}
},
aggs: {
urls: {
terms: {
field: 'meta.http.url'
},
aggs: {
total: {
cardinality: {
field: 'parent_id'
}
}
}
}
}
},
size: 0
}).then(res => {
console.log(JSON.stringify(res))
console.log(res.aggregations.urls.buckets.map(o => {
const res = {};
res[o.key] = o.doc_count / o.total.value;
return res;
}))
})
Is it possible to get the result without doing any additional calculation in Node.js?
Yes, you can leverage pipeline aggregations, and more specifically, the bucket_script one.
The aggs section would look like this instead and in each bucket you'll get the result of the document count divided by the total value stored in the compute section:
aggs: {
urls: {
terms: {
field: 'meta.http.url'
},
aggs: {
total: {
cardinality: {
field: 'parent_id'
}
},
compute: {
bucket_script: {
buckets_path: {
count: "_count",
total: "total"
},
script: "params.count / params.total"
}
}
}
}
}

mongoDB find, update and pull in One Query

I want to do all the find the data from the collection and then want to update some field as well as depending on want to empty the array.
const addCityFilter = (req, res) => {
if (req.body.aCities === "") {
res.status(409).jsonp({ message: adminMessages.err_fill_val_properly });
return false;
} else {
var Cities = req.body.aCities.split(","); // It will make array of Cities
const filterType = { "geoGraphicalFilter.filterType": "cities", "geoGraphicalFilter.countries": [], "geoGraphicalFilter.aCoordinates": [] };
/** While using $addToset it ensure that to not add Duplicate Value
* $each will add all values in array
*/
huntingModel
.update(
{
_id: req.body.id,
},
{
$addToSet: {
"geoGraphicalFilter.cities": { $each: Cities }
}
},
{$set:{filterType}},
).then(function(data) {
res.status(200).jsonp({
message: adminMessages.succ_cityFilter_added
});
});
}
};
Collection
geoGraphicalFilter: {
filterType: {
type:String,
enum: ["countries", "cities", "polygons"],
default: "countries"
},
countries: { type: Array },
cities: { type: Array },
aCoordinates: [
{
polygons: { type: Array }
}
]
}
But as result, the only city array is getting an update. No changes in filterType.
You appear to be passing the $set of filterType as the options argument, not the update argument.
huntingModel
.update(
{
_id: req.body.id,
},
{
$addToSet: {
"geoGraphicalFilter.cities": { $each: Cities }
},
$set: {
filterType
}
}
).then(function(data) {
res.status(200).jsonp({
message: adminMessages.succ_cityFilter_added
});
});

Elasticsearch js query with must and must_not

I am trying to get a query to run with both must and must_not, but have not had any luck with the syntax I am attempting. I see a lot of people on StackOverflow using quotes on both sides like they would be in a Curl call, but this is straight out of a node application.
I will show the query that does work, and I am simply trying to add what I do not want to be included in the outcome. In either case, because this is just trash data that is on a local dev environment, the outcome should match.
First the working query:
client.search({
index: config.ES_INDEX,
type: "issue",
body: {
query: {
match: {
issue_state: 'Closed'
}
},
size: 1000
}
}).then(function(resp){
console.log(util.inspect(resp, {showHidden: false, depth: null}));
}).catch(function(err){
console.log('Failed to search. ' + err.message);
});
Output:
{ took: 5,
timed_out: false,
_shards: { total: 5, successful: 5, failed: 0 },
hits:
{ total: 1,
max_score: 1,
hits:
[ { _index: 'noc_tool',
_type: 'issue',
_id: 'Sy2IQFMLe',
_score: 1,
_source:
{ job_name: 'Job Name 1',
is_maintenance: 'no',
servicenow_id: 'lkjjklh',
type: 'Chase',
start_time: '1970-01-01T23:15:00.000Z',
maint_reminder: null,
update_duration: '4 Hours',
location: 'Test Group',
issue_state: 'Closed',
notes: [ { created_on: 1484063571941, body: 'lkjlkjhlkj' } ],
emailService: { lastEmailAt: 1484237594114 },
created_on: 1484063571941,
updated_on: 1484240538801,
reason: 'because I want to' } } ] } }
Now, the failed query:
client.search({
index: config.ES_INDEX,
type: "issue",
body: {
query: {
bool: {
must: [
{
term: {
issue_state: 'Closed'
}
}
],
must_not: [
{
term: {
is_maintenance: 'yes'
}
}
]
}
},
size: 1000
}
}).then(function(resp){
console.log(util.inspect(resp, {showHidden: false, depth: null}));
}).catch(function(err){
console.log('Failed to search. ' + err.message);
});
Output:
{ took: 6,
timed_out: false,
_shards: { total: 5, successful: 5, failed: 0 },
hits: { total: 0, max_score: null, hits: [] } }
Any help here would be much appreciated.
I ended up using a little "reverse logic" but here is what is working..
return new Promise(function(resolve, reject) {
client.search({
index: config.ES_INDEX,
type: "issue",
body: {
query: {
bool: {
must:[
{
match: {
issue_state: 'Closed'
}
},
{
match: {
is_maintenance: 'no'
}
}
]
}
},
size: 1000
}
}).then(function (resp) {
resolve (resp.hits.hits);
}).catch(function (err) {
reject('Failed to search. ' + err.message);
});

Resources