I need an array of "group" objects from a multi-level-grouped tabulator table where
group = { field: String, name: String }
but when I try to parse the payload of tabulator.getGroups(), I'm missing one of the groups. Is there a tabulator api function for retrieving all the groups from a table? tabulator.getGroups() was the only function I could find in the docs.
https://codepen.io/awcastellano/pen/vMpydW
let data = [
{
"partType": "Disc Brake Pad",
"vehicle": "2019 chevy silverado",
"brand": "Cardone",
"partApplication": "Left Front/MKD794"
},
{
"partType": "Disc Brake Pad",
"vehicle": "2019 ford F150",
"brand": "STS",
"partApplication": "Left Front/MKD794"
},
{
"partType": "Disc Brake Rotor",
"vehicle": "2019 chevy silverado",
"brand": "Cardone",
"partApplication": "Left Front/MKD795"
},
{
"partType": "Disc Brake Pad",
"vehicle": "2019 chevy silverado",
"brand": "Cardone",
"partApplication": "Left Front/MKD795"
},
{
"partType": "Disc Brake Caliper",
"vehicle": "2019 chevy silverado",
"brand": "Cardone",
"partApplication": "Left Front/MKD796"
}
]
let columns = [{
title: "Part",
field: "partApplication"
}, ]
let table = new Tabulator('#tabulator', {
data: data,
columns: columns,
groupBy: ["vehicle", "partType", "brand"]
})
function groups() {
let groups = []
let groupComponents = table.getGroups()
if (groupComponents.length == 0) return groups
for (var i = 0; i < groupComponents.length; i++) {
groups.push({ field: groupComponents[i]._group.field, name: groupComponents[i]._group.key })
}
let groupList = groupComponents[0]._group.groupList
while (groupList.length != 0) {
for (var i = 0; i < groupList.length; i++) {
groups.push({ field: groupList[i].field, name: groupList[i].key })
}
groupList = groupList[0].groupList
}
return groups
}
Call groups() in the codepen console. { field: "brand", name: "STS" } is missing from the array, yet is displayed in the table. I tried to paste the result here but couldn't figure out how to copy the result from codepen.
Thanks in advance!
Check Console
https://codepen.io/dota2pro/pen/NmVzmv
const getAllGroups = function(input){
for(let i=0; i< input.length; i++){
console.log(allRows[i].getGroup());
// Use this or
console.log(allRows[i].getGroup()._group.key
,allRows[i].getGroup()._group.field);
// Use this
console.log('field: ', input[i]._row.modules.group.field,'key:',input[i]._row.modules.group.key );
}}
Related
Below is my code to display review array data which is part of the restaurant collection object:
async get(reviewId) {
const restaurantsCollection = await restaurants();
reviewId = ObjectId(reviewId)
const r = await restaurantsCollection.findOne(
{ reviews: { $elemMatch: { _id : reviewId } } },
{"projection" : { "reviews.$": true }}
)
return r
}
My object looks like:
{
_id: '6176e58679a981181d94dfaf',
name: 'The Blue Hotel',
location: 'Noon city, New York',
phoneNumber: '122-536-7890',
website: 'http://www.bluehotel.com',
priceRange: '$$$',
cuisines: [ 'Mexican', 'Italian' ],
overallRating: 0,
serviceOptions: { dineIn: true, takeOut: true, delivery: true },
reviews: []
}
My output looks like:
{
"_id": "6174cfb953edbe9dc5054f99", // restaurant Id
"reviews": [
{
"_id": "6176df77d4639898b0c155f0", // review Id
"title": "This place was great!",
"reviewer": "scaredycat",
"rating": 5,
"dateOfReview": "10/13/2021",
"review": "This place was great! the staff is top notch and the food was delicious! They really know how to treat their customers"
}
]
}
What I want as output:
{
"_id": "6176df77d4639898b0c155f0",
"title": "This place was great!",
"reviewer": "scaredycat",
"rating": 5,
"dateOfReview": "10/13/2021",
"review": "This place was great! the staff is top notch and the food was delicious! They really know how to treat their customers"
}
How can I get the output as only the review without getting the restaurant ID or the whole object?
So the query operators, find and findOne do not allow "advanced" restructure of data.
So you have 2 alternatives:
The more common approach will be to do this in code, usually people either use some thing mongoose post trigger or have some kind of "shared" function that handles all of these transformations, this is how you avoid code duplication.
Use the aggregation framework, like so:
const r = await restaurantsCollection.aggregate([
{
$match: { reviews: { $elemMatch: { _id : reviewId } } },
},
{
$replaceRoot: {
newRoot: {
$arrayElemAt: [
{
$filter: {
input: "$reviews",
as: "review",
cond: {$eq: ["$$review._id", reviewId]}
}
},
0
]
}
}
}
])
return r[0]
I have a document like below,
{
"id": "7d9fdc2f4846544d62da3421bf011b31",
"al": [
{ "id16": "0x1d42",
"pos": {
"x": 10.32,
"y": 11.13,
"z": 1.22
},
"resultTime": "2020-06-01T20:45:34.976Z"
},
{ "id16": "0x1342",
"pos": {
"x": 0.32,
"y": 1.13,
"z": 13.22
},
"resultTime": "2021-06-01T20:45:34.976Z"
}
.
.
.
],
"Timestamp": 272179,
"Oid": "Onion1",
}
and Design document is like below
{
"id": "_design/GetALwithAnchorID",
"key": "_design/GetALwithAnchorID",
"value": {
"rev": "32-6db6c4e105336d47a6c8e7e8458ee345"
},
"doc": {
"_id": "_design/GetALwithAnchorID",
"_rev": "32-6db6c4e105336d47a6c8e7e8458ee345",
"views": {
"GetALwithAnchorID": {
"map": "function (doc) {\n\n for (var i=0; i<doc.al.length; i++) { \n emit(doc.al[i].id16, doc.al[i].pos);\n }\n \n}\n\n",
"reduce": "_approx_count_distinct"
}
},
"language": "javascript"
}
}
when I query the view like
http://127.0.0.1:5984/rtls/_design/GetALwithAnchorID/_view/GetALwithAnchorID?group_level=1&key=%220x1d42%22
I get the results as below
{"rows":[
{"key":"0x1d42","value":1}
]}
But I want distinct values of id16 and pos of id16. and to sort these distinct values by time and display the values of pos instead of "value":1 when Iquery?
thank you in advance.
OK so not quite the same as this similar answer. Anyone coming across this Q/A, I recommend reading over that answer.
Consider the following emit for your given doc structure:
doc.al.forEach(e => emit(
[e.pos.x, e.pos.y, e.pos.z, e.resultTime], // key
[e.id16, e.pos, e.resultTime]) // value
));
The emit's complex key visualized in the index (loosely not verbatim):
[-3,-2,-1,"2017-10-28T22:56:58.852Z"]
[-3,-2,-1,"2019-01-23T03:33:20.958Z"] **
. . .
[0,0,0,"2016-05-27T01:38:36.305Z"]
[0,0,0,"2016-12-27T05:17:02.255Z"] **
. . .
[1,2,3,"2016-11-14T17:31:59.468Z"]
[1,2,3,"2017-07-17T07:52:38.180Z"] **
Where each ** the last item in the pos group and significantly the most recent resultTime. All due to CouchDB's collation.
Working with CouchDB demands understanding the B-tree, and it's documentation has a great rundown of it in its Reduce/Rereduce documentation.
Now consider this reduce function:
function(keys,values,rereduce) {
return values[0];
}
It doesn't look terribly impressive, but further consider calling the view with these parameters:
{
reduce: true,
group_level: 1,
descending: true
}
By reversing the order of the index scan with descending the reduce function is guaranteed to return the most recent row with respect to resultTime of any given pos group.
Here's a simple demo using pouchDB. It generates 6 documents with random resultTime's and randomly selects pos from a pool of 3. Have a look at the design doc.
async function showReduceDocs(view) {
let result = await db.query(view, {
reduce: true,
group_level: 1,
descending: true
});
// show
debugger;
gel('view_reduce').innerText = result.rows.map(row => `${JSON.stringify(row.value)}`.split(',').join(', ')).join('\n');
return result;
}
async function showViewDocs(view) {
let result = await db.query(view, {
reduce: false,
include_docs: false
});
//show
gel('view_docs').innerText = result.rows.map(row => JSON.stringify(row.key))
.join('\n');
}
function getDocsToInstall(count) {
// design document
const ddoc = {
"_id": "_design/SO-66231293",
"views": {
"id16": {
"map": `function (doc) {
doc.al.forEach((e) => emit([e.pos.x, e.pos.y, e.pos.z, e.resultTime],[e.id16, e.pos, e.resultTime]));
}`,
"reduce": `function(keys,values,rereduce) {
return values[0];
}`
}
}
};
// create a set of random documents.
let docs = new Array(count);
let docId = 65;
const posSeed = [{
x: 0,
y: 0,
z: 0
},
{
x: 1,
y: 2,
z: 3
},
{
x: -3,
y: -2,
z: -1
}
];
const dateSeed = [new Date(2000, 0, 1), new Date(), 0, 24];
while (count--) {
let n = 6;
let doc = {
_id: String.fromCharCode(docId++),
al: new Array(n)
};
while (n-- > 0) {
doc.al[n] = {
"id16": "0x000" + n,
"pos": posSeed[Math.floor(Math.random() * 100) % 3],
"resultTime": randomDate(...dateSeed).toISOString()
};
}
docs[count] = doc;
}
docs.push(ddoc);
return docs;
}
const db = new PouchDB('SO-66231293', {
adapter: 'memory'
});
(async() => {
// install docs and show view in various forms.
await db.bulkDocs(getDocsToInstall(6));
gel('content').classList.remove('hide')
showReduceDocs('SO-66231293/id16');
showViewDocs('SO-66231293/id16');
})();
const gel = id => document.getElementById(id);
/*
https://stackoverflow.com/questions/31378526/generate-random-date-between-two-dates-and-times-in-javascript/31379050#31379050
*/
function randomDate(start, end, startHour, endHour) {
var date = new Date(+start + Math.random() * (end - start));
var hour = startHour + Math.random() * (endHour - startHour) | 0;
date.setHours(hour);
return date;
}
<script src="https://cdn.jsdelivr.net/npm/pouchdb#7.1.1/dist/pouchdb.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<div id='content' class='hide'>
<div>View: reduce</div>
<pre id='view_reduce'></pre>
<hr/>
<div>View: complex key</div>
<pre id='view_docs'></pre>
</div>
Edit
Amended the demo snippet according to OP's comments.
Is it possible to sort or re-arrange the json object with another array set
Here is the JSON object with url key
var items-array = [
{
"_source":{
"Edition":{
"Values":{
"title":"new featured parallex",
"indexContent":" new "
}
},
"url":"/demo-inline-component-capability/demo-of-featured-parallex"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"demo of event careers",
"description":"careers",
"indexContent":" careers demo urrent"
}
},
"url":"/demo-inline-component-capability/demo-of-event-card"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"reference event cards",
"indexContent":" reference event cards <cmp id=\"jvcbt0if\" class=\"cmp\" contenteditable=\"false\"> orange"
}
},
"url":"/demo-inline-component-capability/demo-of-ref-event-card"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"demo of video playlists",
"indexContent":" demo "
}
},
"url":"/demo-inline-component-capability/demo-of-video-playlist"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"demo of data point set careers",
"description":"careers",
"indexContent":" careers demo of data point set red"
}
},
"url":"/demo-inline-component-capability/demo-of-data-point-set"
},
"sort":[
1555320208440
]
},
{
"_source":{
"Edition":{
"Values":{
"title":"Xfinity TV’sa Lunar New Year collection is a celebration of the vast contributions the Asian American community makes to entertainment across comcast careers",
"description":"mobile name",
"indexContent":" mobile name "
}
},
"url":"/lunar-festival"
},
"sort":[
1551093922066
]
}
]
To match with sorting array of url
var sortingArr = ["/demo-inline-component-capability/demo-of-video-playlist","/demo-inline-component-capability/demo-of-featured-parallel","/demo-inline-component-capability/demo-of-ref-event-card","/demo-inline-component-capability/demo-of-event-card"]
Unfortunately, I don’t have any IDs to keep track on. I would need to priority the items-array to match the sortingArr as close as possible.
Any idea how this can be done.
The code below will output a new array newArr with whatever it finds in the order provided. It will not include any items that aren't in the sortingArr.
var newArr = [];
sortingArr.forEach(s => {
var i = itemsArray.find(o => {
return o["_source"]["url"] === s;
})
if(i != null) {
newArr.push(i);
}
});
newArr.forEach(o => {
console.log(o);
});
Also, the sortingArr is malformed. It should be:
var sortingArr = ["/demo-inline-component-capability/demo-of-video-playlist","/demo-inline-component-capability/demo-of-featured-parallel","/demo-inline-component-capability/demo-of-ref-event-card","/demo-inline-component-capability/demo-of-event-card"]
You can implement a custom sort for this
const sorted = items_array.sort((a, b) => {
// take index of URL from sorting array
const ai = sortingArr.findIndex(x => a._source.url === x);
const bi = sortingArr.findIndex(x => b._source.url === x);
// handle edge case where lower URL is sortable and other isn't
if (ai === -1 && bi > ai) return 1;
// handle edge case where higher URL is sortable and other isn't
if (bi === -1 && ai > bi) return -1;
// handle all other scenarios
return ai - bi;
});
Example
var items_array = [
{
"_source":{
"Edition":{
"Values":{
"title":"new featured parallex",
"indexContent":" new "
}
},
"url":"/demo-inline-component-capability/demo-of-featured-parallex"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"demo of event careers",
"description":"careers",
"indexContent":" careers demo urrent"
}
},
"url":"/demo-inline-component-capability/demo-of-event-card"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"reference event cards",
"indexContent":" reference event cards <cmp id=\"jvcbt0if\" class=\"cmp\" contenteditable=\"false\"> orange"
}
},
"url":"/demo-inline-component-capability/demo-of-ref-event-card"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"demo of video playlists",
"indexContent":" demo "
}
},
"url":"/demo-inline-component-capability/demo-of-video-playlist"
},
"isPromoted":true
},
{
"_source":{
"Edition":{
"Values":{
"title":"demo of data point set careers",
"description":"careers",
"indexContent":" careers demo of data point set red"
}
},
"url":"/demo-inline-component-capability/demo-of-data-point-set"
},
"sort":[
1555320208440
]
},
{
"_source":{
"Edition":{
"Values":{
"title":"Xfinity TV’sa Lunar New Year collection is a celebration of the vast contributions the Asian American community makes to entertainment across comcast careers",
"description":"mobile name",
"indexContent":" mobile name "
}
},
"url":"/lunar-festival"
},
"sort":[
1551093922066
]
}
]
var sortingArr = [
"/demo-inline-component-capability/demo-of-video-playlist",
"/demo-inline-component-capability/demo-of-featured-parallel",
"/demo-inline-component-capability/demo-of-ref-event-card",
"/demo-inline-component-capability/demo-of-event-card"
];
console.log('BEFORE');
for (var x of items_array) {
console.log(x._source.url);
}
const sorted = items_array.sort((a, b) => {
// take index of URL from sorting array
const ai = sortingArr.findIndex(x => a._source.url === x);
const bi = sortingArr.findIndex(x => b._source.url === x);
// handle edge case where lower URL is sortable and other isn't
if (ai === -1 && bi > ai) return 1;
// handle edge case where higher URL is sortable and other isn't
if (bi === -1 && ai > bi) return -1;
// handle all other scenarios
return ai - bi;
});
console.log('AFTER');
for (var y of sorted) {
console.log(y._source.url);
}
Hi I have come with this O(n) solution
you can create an object having keys as the url and value as list of objects corresponding to the URL
Then based on the sorting order URL present in the sortArray you can iterate over the sort array and get the corresponding list of objects in the object and merge them to get the final array
function sortItem(items_array, sortUrl) {
let urlMap = {}
for (item of items_array) {
let url = item._source.url
if (!urlMap.hasOwnProperty(url)) {
urlMap[url] = []
}
urlMap[url].push(item)
}
let finalList =[]
for (url of sortUrl){
if(urlMap.hasOwnProperty(url)){
let itemList = urlMap[url]
finalList = finalList.concat(itemList)
}
}
return finalList
}
sortUrl is the list of urls to sort the items_array
var sortingArr = ["/demo-inline-component-capability/demo-of-video-playlist","/demo-inline-component-capability/demo-of-featured-parallel","/demo-inline-component-capability/demo-of-ref-event-card","/demo-inline-component-capability/demo-of-event-card"]
I am stuck with this issue for a few days now. I am not able to format the values according to the given format.
I have 2 Array objects.
var name = ["sam","Anthony"];
var age = ["4","10"];
The name and age array may contain more values in it. So it means that the 2 arrays above are dynamic.
I need to extract values from these arrays and add them in the Item section as shown in the following code. However, I am not able to hardcode the array content as this array is dynamic in size. It may contain more student records in it. In that case How am I able to construct the following params variable after populating the values of the name and age arrays ?
var params = {
RequestItems: {
"Student": [
{
PutRequest: {
Item: {
"name": "sam",
"age": "4"
}
}
},
{
PutRequest: {
Item: {
"name": "Anthony",
"age": "10"
}
}
}
]
}
};
Use the map function:
var names = ["sam", "Anthony"];
var age = ["4", "10"];
var params = {
RequestItems: {
"Student": names.map(function(c, index) {
return {
PutRequest: {
Item: {
"name": c,
"age": age[index]
}
}
};
})
}
};
alert(JSON.stringify(params, null, 4));
I have an array with countries with the following structure:
{
"code": "ZW",
"name": "Zimbabwe",
"zipPattern": "[\\s\\S]*",
"states": [
{
"name": "Bulawayo"
},
{
"name": "Harare"
},
{
"name": "Manicaland"
},
{
"name": "Mashonaland Central"
},
{
"name": "Mashonaland East"
},
{
"name": "Mashonaland West"
},
{
"name": "Masvingo"
},
{
"name": "Matabeleland North"
},
{
"name": "Matabeleland South"
},
{
"name": "Midlands"
}
]
}
I am trying to insert them into MongoDb using MongoSkin with the following code
var countries = require('./mongo/ready/Countries');
db.collection('countries').find().toArray(function (err, result) {
if (result.length === 0) {
for (var i = 0; i < countries.length; i++) {
var obj = countries[i];
var states = obj.states;
db.collection('countries').insert({
name: obj.name,
code: obj.code,
zipPattern: obj.zipPattern
}, function (error, countryResult) {
var id = countryResult[0]._id;
for (var j = 0; j < states.length; j++) {
var state = states[j];
db.collection('states').insert({
countryId: id,
name: state.name
}, function (stateError, stateResult) {
if (stateError) console.log(stateError);
console.log(stateResult);
});
}
});
}
}
});
but the code inserts the states of the last country in the array (Zimbabwe) for each country in the array instead of the correct states. How can I fix it?
Generally we don't use async query(insert) between sync loop(simple for loop). Its give us abnoramal results. Node provides async loop to overcome this.
First of all require async module for this.
var async = require('async');
Now you can use following code for insertion of countries and their respective states
async.each(countries, function(obj, callback) {
var states = obj.states;
db.collection('countries').insert({
name: obj.name,
code: obj.code,
zipPattern: obj.zipPattern
}, function(error, countryResult) {
if (error) {
callback(error);
} else {
var id = countryResult[0]._id;
async.each(states, function(state, callback) {
db.collection('states').insert({
countryId: id,
name: state.name
}, function(stateError, stateResult) {
if (stateError) {
callback(stateError);
} else {
callback();
}
});
});
callback();
}
}); }, function(err) {
if (err) {
// handle error here
} else {
// do stuff on completion of insertion
} });
Thanks