PouchDB quick search: Search within for loop and return results AFTER for loop finish - for-loop

I have the following document structure:
{
"_id": "car_1234",
"_rev": "1-9464f5d70547c255a423ff8dae653db1",
"Tags": [
"Audi",
"A4",
"black"
],
"Car Brand": "Audi",
"Model": "A4",
"Color": "black",
"CarDealerID": "5"
}
The Tags field stores the information of the document in a list. This structure needs to stay like this. Now the user has the opportunity to search for cars in a HTML text input field, where a , represents a separation between cars. Let's take the following example:
black Audi, pink Audi A4
Here the user wants to find a black Audi or a pink Audi A4. My approach of querying through the database is by splitting the entered words to the following structure [["black", "Audi"],["pink", "Audi", "A4"]] and to search inside the Tags field of each document in the db if all the words in a subarray (e.g. "black" and "Audi") are existent and to return the CarDealerID.
///Before this I return the word list as described
}).then(function (wordList) {
results = [];
for (var i = 0; i < userWords.length; i++) {
//Check if the object is a single word or an array of words
if (wordList[i].constructor === Array) {
//Recreate the words in the array as one string
wordString = ""
wordList[i].forEach(function (part) {
wordString += part + " "
})
wordString = wordString.trim()
//Search for the car
car_db.search({
query: wordString,
fields: ["Tags"],
include_docs: true
}).then(function(result) {
result.rows.forEach(function (row) {
results.push(row.doc.CarDealerID)
})
})
} else {
car_db.search({
query: userWords[i],
fields: ["Tags"],
include_docs: true
}).then(function(result) {
result.rows.forEach(function (row) {
results.push(row.doc.CarDealerID)
})
})
}
return results
}).then(function(results) {
console.log(results)
}).catch(function (err) {
console.log(err)
});
My Problem
My problem is now that the results are returned before the for loop finishes. This is probably because it is an async procedure and the result should wait to be returned until this async is finished. But I don't know how to achieve that. I hope someone can help me out.

Thanks to Nolan Lawson's Blog (Rookie Mistake #2) I could figure it out. Instead of the for loop, I use
return Promise.all(wordList.map(function (i) {
results = [];
//
//Same Code as before
//
//Return results inside the map function
return results;
}));

Related

How to load and save a work order record using the map reduce script

I am trying to only load and save a work order record using the map-reduce script. But I don't see logs for loaded work orders or saved work orders. the script is executing only until work_order_Id. Please Help!   
Below is my code...
function getInputData(){
var process_data =[];
try{
var workorderSearchObj = search.create({
type: "workorder",
filters:
[
["type","anyof","WorkOrd"],
"AND",
["mainline","is","T"],
"AND",
["status","anyof","WorkOrd:A","WorkOrd:B","WorkOrd:D"]
],
columns:
[
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "tranid", label: "Document Number"})
]
});
var searchResultCount = workorderSearchObj.runPaged().count;
log.debug("workorderSearchObj result count",searchResultCount);
workorderSearchObj.run().each(function(result){
// .run().each has a limit of 4,000 results
var work_Order = result.getValue({name:'internalid'});
var document_no = result.getValue({name:'tranid'});
process_data.push({
'work_Order':work_Order,
'document_no':document_no
});
return true;
});
}catch(error){
log.debug(error);
}
return process_data;
}
function map(context){
var process_data=JSON.parse(context.value);
log.debug('process_data',process_data);
var work_order_Id = process_data.work_Order;
log.debug("work_order_Id",work_order_Id);
var work_Order_obj = record.load({
type: record.Type.WORK_ORDER,
id: work_order_Id,
isDynamic: true
});
log.debug("work_Order_obj",work_Order_obj);
var recId=work_Order_obj.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recId",recId);
}
I am trying to load and save work order record. But its not executing.I am trying to load and save a work order record. but it's not loading.
I usually like to simply return saved searches in getInputData because it's consistent to work with and you don't have to fuss with the going over 4k search results and having to return arrays of objects that you put together yourself. Usually transforming data to be in the format you want is best done in the map stage.
/**
* #NScriptType MapReduceScript
* #NApiVersion 2.x
*/
define(["N/search", "N/record"], function (search, record) {
function getInputData() {
// run a saved search of work orders
return search.create({
type: "workorder",
filters: [
["type","anyof","WorkOrd"],
"AND",
["mainline","is","T"],
"AND",
["status","anyof","WorkOrd:A","WorkOrd:B","WorkOrd:D"]
],
columns: [
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "tranid", label: "Document Number"}),
]
});
}
function map(context) {
// get the work order id
var workOrderId = JSON.parse(context.value).id;
log.debug("workOrderId", workOrderId);
// load the work order
var wordOrderRecord = record.load({
type: record.Type.WORK_ORDER,
id: work_order_Id,
isDynamic: true,
});
log.debug("wordOrderRecord", wordOrderRecord);
// save the work order
var recId = wordOrderRecord.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recId",recId);
}
function summarize(context) {
// log any errors that might occur
context.mapSummary.errors.iterator().each(function (_, errJson) {
var error = JSON.parse(errJson);
log.error({title: error.name, details: error.message});
return true;
});
}
return {
getInputData: getInputData,
map: map,
summarize: summarize,
};
})

Need to display crossfilter data array values in separate lines instead of comma separated values in a single line

My data looks like below:
var data = [{
"Id": "1",
"startTime": 1554750660000,
"endTime": 1554751320000,
"Alerts": [
"Alert1","Alert2"
],
"Apps": [
"App1","App2"
]
}]
I have to display above data using crossfilter-data-table.
Currently, I am able to display the data like below:
StartTime EndTime Apps Alerts
04/08/2019 12
12:42:00 PM 12:49:00 PM App1,App2 Alert1,Alert2
Instead, I want to show it in below format.
Changes are: the array values of columns Apps, Alerts are not displayed as comma separated values. Instead they are shown in a separate line one after the other.
StartTime EndTime Apps Alerts
04/08/2019 12
12:42:00 PM 12:49:00 PM App1 Alert1
App2 Alert2
My current code looks like below:
import React from "react";
import * as dc from "dc";
import "dc/dc.css";
import * as d3 from "d3";
import { ChartTemplate } from "./chartTemplate";
import { css } from "glamor";
const tableFunc = (divRef, ndx) => {
const summaryTable = dc.dataTable(divRef);
const dimension = ndx.dimension(d => d.StartTime);
summaryTable
.dimension(dimension)
.showGroups(true)
.size(10000)
.group(d => {
return d.hour;
})
.columns([
{
label: "Start Time",
format: function(d) {
return d. startTime;
}
},
{
label: "End Time",
format: function(d) {
return d. endTime;
}
},
{
label: "Apps",
format: function(d) {
return d.Apps;
}
},
{
label: "Alerts",
format: function(d) {
return d.Alerts;
}
}
])
.sortBy(function(d) {
return d.startTime;
})
.order(d3.descending)
.on("renderlet", function(table) {
table.selectAll(".dc-table-group").classed("info", true);
});
return summaryTable;
};
const style = css({
"& tr": {
"&:hover": {
background: "#dddd"
}
},
"& td": {
textAlign: "left",
borderTop: "1px solid #ddd"
}
});
export const DataTable = props => (
<ChartTemplate
chartFunction={tableFunc}
styles={style}
title="Summary"
/>
);
What change i should do to display details in required format as above.Please help I'm really new to react, crossfilter and d3.
Assuming it's okay to display all the array values in one cell, I think the easiest way to get what you want would be simply to format the cell using <br> - the line break element.
E.g.
{
label: "Apps",
format: function(d) {
return d.Apps.join('<br>');
}
},
It would be a lot more difficult to create extra rows, since data table rows usually correspond 1:1 with rows of the data set.
Adding links
#zubug55 commented
In my real data, alerts look like:
"Alerts": [ "abc#link1","def#link2" ]
How do I break each abc#link1 on # and make abc a link to the url link1?
It's probably easiest to generate the anchor elements in HTML at the same time, like
return d.Alerts.map(function(a) {
var parts = a.split('#');
return '' + parts[0] + '';
}).join('<br>');

ElasticSearch API under Data Tables fnServerData

I want to fill the datatable data from elasticsearch js api. For that I have a code like this.
var oTable = $('#myTable').dataTable({
columns: [
{ title: "Title" }
],
'bProcessing': true,
'bServerSide': true,
"bPaginate": true,
"bSort": false,
"asStripeClasses": [],
"fnServerParams": function (aoData) {
aoData.push(
{"name":"search", "value": $('#title_search').val()},
);
},
'fnServerData': function (sSource, aoData, fnCallback) {
var searchval,sortval,sortorder;
aoData.map(function(i) {
var search = i.name;
if(search =='search') {
searchval = i.value;
}
});
/*Query ElasticSearch */
client.search({
index: indexname,
type: indextype,
from: 0,
size: 10,
body: {
query: {
"query_string": {
"query": searchval + '*',
"fields": ["title", "number"]
}
}
}
}, function (error, response) {
fnCallback(response);
});
}
});
I am able to fetch the results from the above call. But, when I try to search in the Data Table, the results are appending for every letter searching.
function search(e) {
otTable.fnDraw();
}
For Example, I try to search for London. When I type L it is appending all results starting with letter L, and when I type O then it is again appending all results starting with Lo.
I am getting the correct response from ES, I think there is a problem at Data Tables end while appending the data.
Any ideas what I am doing wrong here.

Showing sum of multiple values with amCharts

I would like to show sum of multiple values as one chart output with amCharts. I am using dataLoader with JSON to get the data. I know I have to create a function for but I couldn't understand how to get the data from the dataLoader to calculate
{
"balloonText": "[[title]] of [[valueAxis]]:[[value]]",
"lineThickness": 3,
"id": "sumValue",
"title": "sum Value",
"valueField": (function() {
var sumValues = "calculation";
return sumValues
}
this attempt is probably not correct but this is how I started
{
"balloonText": "[[title]] of [[valueAxis]]:[[value]]",
"lineThickness": 3,
"id": "LoadigTime",
"title": "Loadig Time",
"valueField": (function() {
var sumValues = (HomePageLoad + LoginToParametersLoad + ParametersLoad + AlarmsLoad + SwitchSideLoad + LoginToAdminLoad + AdminLoad) / 7;
return sumValues
})
}
valueField cannot be a function, only a string reference to a field in your data.
If the chart is meant to be displaying the sum of all of those fields in your data as a chart, simply add logic to your postProcess callback to create a new dataset containing your sums, e.g.
postProcess: function(data) {
var newData = [];
data.forEach(function(dataItem) {
var item = {
YOUR_CATEGORY_FIELD: dataItem.YOUR_CATEGORY_FIELD, //replace with your category field name
sum: 0
};
//loop through your item's keys and sum everything up, filtering out
//your category property
item.sum = Object.keys(dataItem).reduce(function(sum, key) {
if (key !== "YOUR_CATEGORY_FIELD") {
sum += dataItem[key]
}
return sum;
}, 0);
newData.push(item);
});
return newData;
},
// ...
graphs: [{
valueField: "sum",
// other props here
}]

ChartJS in Datatable cell performance

So for some reason I have to put a tiny chart into a column cell.
I did it with a simple div and initizialized every single chart:
<div>
<canvas id="6" height="50px" width="150px"></canvas>
</div>
jsFiddle
Which works great for 10 dataset or 20. But i got a huge datatable with 380 rows and after "2 minutes" of waiting it even loads the charts for every single table row.
Is there a better way to do it, or boost performance?
I found the solution.
Like mentioned in this post: Pagination triggers
I call a function which inits the visible charts on datatable draw. Means i only draw them when they get viewed. Nice performance and super slim solution.
$('#Table')
.on( 'draw.dt', function () { initSparkline(); } )
.dataTable();
});
Another option might be to use the drawCallback option to use data in the table to render charts for the visible rows each time the DataTable is re-drawn for a page change.
Below is an simplified example of how this might be done for a doughnut chart.
$('#dataTableId').DataTable({
// I use the "columns" option to tell each column what data to show.
// One column should have a uniquely id'ed canvas.
"columns": [
{ "data": "id" },
{ "data": "A" },
{ "data": "B" },
{ "data": function(row){
return "<canvas height=\"40px\" width=\"40px\" id=\"chart"+row.id+"\"></canvas>";
},
"orderable": false}
],
"drawCallback": function() {
// Get data, only from the rows displayed on the current page.
var data = this.api().rows({page:'current'}).data();
// The first draw appears to have a length of 0,
// but subsequent ones have length equal to number of rows drawn.
if (data.length !== 0){
// Loop through each row to render each chart
for (var i = 0; i < data.length; i++) {
// Find the chart intended for this data
var ctx = $("#chart"+data[i].id);
// Make the chart
var newChart = new Chart(ctx, {
"type": "doughnut",
"data": {
"labels": [
"A",
"B"
],
"datasets": [{
"data": [data[i].A,data[i].B]
}],
},
}) // /Chart
}
}
}
// In a real table, the object passed into the DataTable() function will
// probably also use other options, such as "ajax", "serverSide" or
// "pageLength". For simplicity, only "columns" and "drawCallback" are
// shown in this example.
}); // /DataTable

Categories

Resources