Given:
var object = {key: value, key1: value, key2: value}
var array = [{object}, {object1}, {object2}, {object3}]
I want to use the parse javascript SDK to delete object 3 and 4 from the array. Using their key2 values. How do I do this?
I believe it goes something like:
object.remove("the key", [object2value2, object3value2])
I need more detail on how to articulate the key and the value. I looked at the docs and I just can't figure it out. I've spent days on this. Humor me, please I'm a newbie and I'm suffering!
THIS IS WHAT SHOWS IN MY TERMINAL AFTER MY PARSE QUERIES WHEN I LIST.GET("OBJECT");
I'd like to delete objects by _id. At the very bottom you see 'false' where I do LIST.REMOVE("_id", [array of _ids]):
[ { _account: 'YzzrzBrO9OSzo6BXwAvVuL5dmMKMqkhOoEqeo',
_id: 'QllVljV252iNZej9VQgBCYkEyD4Do9fvZMAvmK',
amount: 2307.15,
category: [ 'Shops', 'Computers and Electronics' ],
category_id: '19013000',
date: '2014-06-23',
meta: { location: [Object] },
name: 'Apple Store',
pending: false,
score: { location: [Object], name: 0.2 },
type: { primary: 'place' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'NQQVQJVDgDhj90JvnXkMt1jm06eqzji5JvO52Z',
amount: 3.19,
category: [ 'Food and Drink', 'Restaurants', 'Coffee Shop' ],
category_id: '13005043',
date: '2014-06-21',
meta: { location: [Object] },
name: 'Gregorys Coffee',
pending: false,
score: { location: [Object], name: 0.2 },
type: { primary: 'place' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'Jwwrw1rnjnfXPvmG9KlZtDoXbQnW1VIMvwrMKp',
amount: 80,
category: [ 'Transfer', 'Withdrawal', 'ATM' ],
category_id: '21012002',
date: '2014-06-08',
meta: { location: [Object] },
name: 'ATM Withdrawal',
pending: false,
score: { location: [Object], name: 1 },
type: { primary: 'special' } },
{ _account: 'mjj9jp92z2fD1mLlpQYZI1gAd4q4LwTKmBNLz',
_id: 'aWWVW4VqGqIdaP495pmetGRqAVKrLRFMD5bMrX',
amount: -240,
category: [ 'Transfer', 'Account Transfer' ],
category_id: '21001000',
date: '2014-06-02',
meta: { location: {} },
name: 'Online Transfer from Chk ...1702',
pending: false,
score: { location: {}, name: 1 },
type: { primary: 'special' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'ZnnVnDVbybCqG4DV1BMgCPyAgyDz9vSA2Y5AG1',
amount: 240,
category: [ 'Transfer', 'Account Transfer' ],
category_id: '21001000',
date: '2014-06-01',
meta: { location: {} },
name: 'Online Transfer to Sav ...9606',
pending: false,
score: { location: {}, name: 1 },
type: { primary: 'special' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'WOOVOlVrqrHaVDlAdGPmUAKg5k4qBafkZjRkb2',
amount: -0.93,
category: [ 'Interest' ],
category_id: '15000000',
date: '2014-05-17',
meta: { location: {} },
name: 'Interest Payment',
pending: false,
score: { location: {}, name: 0.2 },
type: { primary: 'unresolved' } },
{ _account: 'YzzrzBrO9OSzo6BXwAvVuL5dmMKMqkhOoEqeo',
_id: '600r0LrVvViXjq96lBpdtyOWboBvzmsaZoeaVz',
amount: 12.74,
date: '2014-05-12',
meta: { location: [Object] },
name: 'Golden Crepes',
pending: false,
score: { location: [Object], name: 0.2 },
type: { primary: 'place' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'pQQJQ9J0k0hqAVbDwMmYCrajm2JE6OUNBvwNYa',
amount: 7.23,
category: [ 'Food and Drink', 'Restaurants', 'Coffee Shop' ],
category_id: '13005043',
date: '2014-05-09',
meta: { location: [Object] },
name: 'Krankies Coffee',
pending: false,
score: { location: [Object], name: 0.2 },
type: { primary: 'place' } },
{ _account: 'YzzrzBrO9OSzo6BXwAvVuL5dmMKMqkhOoEqeo',
_id: '2DD4Dl4nJnCPn4YRJK95hvwgWda5y2SWdDkW6m',
amount: 118.23,
category: [ 'Shops', 'Digital Purchase' ],
category_id: '19019000',
date: '2014-04-26',
meta: { location: {} },
name: 'Banana Republic',
pending: false,
score: { location: {}, name: 0.2 },
type: { primary: 'digital' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'oGGNG1NwYwUZQGOB5yjlhYMKG6yMQGtaON9aLd',
amount: -800,
category: [ 'Transfer', 'Third Party', 'Venmo' ],
category_id: '21010001',
date: '2014-04-20',
meta: { location: {} },
name: 'Venmo Cashout 18375552',
pending: false,
score: { location: {}, name: 1 },
type: { primary: 'special' } },
{ _account: 'V66V6EVOpOIVGQEkNpX1HkwDKX0XWLUga5B2Y',
_id: 'pQQJQ9J0k0hqAVbDwMmYCrapBJba4BSNBvwNYk',
amount: 120,
category: [ 'Transfer', 'Third Party', 'Venmo' ],
category_id: '21010001',
date: '2014-04-19',
meta: { location: {} },
name: 'Venmo Payment 16991172',
pending: false,
score: { location: {}, name: 1 },
type: { primary: 'special' } },
{ _account: 'YzzrzBrO9OSzo6BXwAvVuL5dmMKMqkhOoEqeo',
_id: '055z5gzVyVfzlBnEOqYvcoLL1ZgOWJhkrWMkv2',
amount: 5.32,
category: [ 'Food and Drink', 'Restaurants', 'Coffee Shop' ],
category_id: '13005043',
date: '2014-04-17',
meta: { location: [Object] },
name: 'Octane Coffee Bar and Lounge',
pending: false,
score: { location: [Object], name: 0.2 },
type: { primary: 'place' } },
{ _account: 'YzzrzBrO9OSzo6BXwAvVuL5dmMKMqkhOoEqeo',
_id: 'LvvrvyrOGOS2e5yE0Bdki45Y1ndVlgfoZ2zoOp',
amount: 28.57,
category: [ 'Food and Drink', 'Restaurants', 'Pizza' ],
category_id: '13005012',
date: '2014-04-11',
meta: { location: [Object] },
name: 'Papa Johns Pizza',
pending: false,
score: { location: [Object], name: 0.2 },
type: { primary: 'place' } },
{ _account: 'mjj9jp92z2fD1mLlpQYZI1gAd4q4LwTKmBNLz',
_id: 'rEEwENwnznCQvkm61wRziKlMRPqaYztnR4vn61',
amount: -3042.44,
category: [ 'Transfer', 'Payroll' ],
category_id: '21009000',
date: '2014-03-27',
meta: { location: {} },
name: 'Company Payroll',
pending: false,
score: { location: {}, name: 1 },
type: { primary: 'special' } },
{ _account: 'AaaraZrLqLfzRYoAPlb6ujPELWVW4dTK4eJWj',
_id: '944r40rPgPU2nXqzMYolS5nyo6Eo9OuqrlDkB',
amount: 200,
category: [ 'Transfer', 'Withdrawal', 'ATM' ],
category_id: '21012002',
date: '2014-07-21',
meta: { location: [Object] },
name: 'ATM Withdrawal',
pending: false,
score: { location: [Object], name: 1 },
type: { primary: 'special' } },
{ _account: 'AaaraZrLqLfzRYoAPlb6ujPELWVW4dTK4eJWj',
_id: 'rEEwENwnznCQvkm61wZ9uey62Pjy5YTqgYGDK',
amount: 240,
category: [ 'Transfer', 'Account Transfer' ],
category_id: '21001000',
date: '2014-07-24',
meta: { location: {} },
name: 'Online Transfer from External Sav ...3092',
pending: false,
score: { location: {}, name: 1 },
type: { primary: 'special' } } ]
false
The operand to remove needs to equal the object being removed. So first find the object you wish to remove...
var array = myObject.get("theArrayCol");
var removeMe;
for (var i=0; i < array.length; i++) {
if (array[i].key2 == "this one should be removed")
removeMe = array[i];
}
then remove it...
myObject.remove("theArrayCol", removeMe);
EDIT - based on our chat, here's how to apply this in your situation. I broke the code up into simpler functions, each doing an easily definable operation. I hope it makes it easier to understand, and I think its good programming practice anyway...
// token is your key to search the Transaction table in parse
function transactionWithToken(token) {
var query = new Parse.Query("Transactions");
query.equalTo("access_token", token);
query.select("transactions");
return query.first();
}
// array is the value of the array column on the Transaction table
// transactionId is a string that might match the value of the _id property in the array of objects
function transactionInArrayWithId(array, transactionId) {
for (var i=0; i<array.length; i++) {
if (array[i]._id == transactionId) return array[i];
}
return undefined;
}
function removeTransactionWithId(transaction, transactionId) {
var array = transaction.get("transactions");
var t = transactionInArrayWithId(array, transactionId);
transaction.remove("transactions", t);
}
// token is the key to the Transaction table
// transactionIds is an array of ids to remove from the Transaction object's transactions array
function removeTransactionsWithIdsFromToken(token, transactionIds) {
return transactionWithToken(token).then(function(result) {
for (var i=0; i<transactionIds.length; i++) {
removeTransactionWithId(result, transactionIds[i]);
}
return result.save();
});
}
This would be easier to understand if the column name and the table name weren't so similar. Also, underscorejs is great at this sort of array management.
you can try to filter it.
For example if you want to remove all objects which key 'k3' has value of 3;
var obj1 = {k1: 1, k2: 2, k3: 3};
var obj2 = {k1: 4, k2: 5, k3: 6};
var obj3 = {k1: 7, k2: 8, k3: 9};
var array = [obj1, obj2, obj3];
var badValue = 3;
var result = array.filter(function(obj){
return obj.k3 !== badValue;
});
Related
I have such an object with newComments:
const newComments = {
commentDirectoryId: "ee63997c-01d5-ec11-8dad-e116bd673e14",
comments: [
{
id: "123",
status: {
entity: null,
id: "1a913152-7809-ec11-8daa-90600b960f93",
name: "In work",
parentId: null,
},
},
{
id: "124",
status: {
entity: null,
id: "1a913152-7809-ec11-8daa-90600b960f94",
name: "Note",
parentId: null,
},
},
{
id: "125",
status: {
entity: null,
id: "1a913152-7809-ec11-8daa-90600b960f95",
name: "Canceled",
parentId: null,
},
},
{
id: "126",
status: {
entity: null,
id: "1a913152-7809-ec11-8daa-90600b960f96",
name: "Done",
parentId: null,
},
},
],
dataType: "Tags",
idAttributeApprovalName: "12-015-123",
};
There are also filters:
const values = ["Note", "Canceled", "Done"];
My task is to return only comments that are not equal to keys:
comment.status.name !== "Note" | "Canceled" |"Done"
In other words:
const newComments = {
commentDirectoryId: "ee63997c-01d5-ec11-8dad-e116bd673e14",
comments: [
{
id: "123",
status: {
entity: null,
id: "1a913152-7809-ec11-8daa-90600b960f93",
name: "In work",
parentId: null,
},
},
],
dataType: "Tags",
idAttributeApprovalName: "12-015-123",
};
You can use Array#filter in conjunction with Array#every or Array#includes.
const newComments={commentDirectoryId:"ee63997c-01d5-ec11-8dad-e116bd673e14",comments:[{id:"123",status:{entity:null,id:"1a913152-7809-ec11-8daa-90600b960f93",name:"In work",parentId:null}},{id:"124",status:{entity:null,id:"1a913152-7809-ec11-8daa-90600b960f94",name:"Note",parentId:null}},{id:"125",status:{entity:null,id:"1a913152-7809-ec11-8daa-90600b960f95",name:"Canceled",parentId:null}},{id:"126",status:{entity:null,id:"1a913152-7809-ec11-8daa-90600b960f96",name:"Done",parentId:null}},],dataType:"Tags",idAttributeApprovalName:"12-015-123"};
const values = ["Note", "Canceled", "Done"];
newComments.comments = newComments.comments.filter(c =>
values.every(v => c.status.name !== v));
// or !values.includes(c.status.name) if no complex matching logic is required
console.log(newComments);
I'm looking for pointers on how to approach diffing two nested objects with some semantic awareness. As an example, take an object that represents a company org chart. Each employee has some properties about them like their role and salary, as well as an "employees" array which contains any employees that report to them
const employees = [
{
employee: 'John',
employeeId: '1',
roleDetails: {
title: 'CEO',
compensation: {
bonus: 10000,
salary: 899999
}
},
employees: [
{
employee: 'Will',
employeeId: '4',
roleDetails: {
title: 'Assistant to CEO',
compensation: {
bonus: 9919,
salary: 17728
}
},
employees: []
},
{
employee: 'Jane',
employeeId: '5',
roleDetails: {
title: 'Head of Operations',
compensation: {
bonus: 8190,
salary: 17492
}
},
employees: [
{
employee: 'Tom',
employeeId: '6',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1839,
salary: 18429
}
},
employees: []
},
{
employee: 'Patricia',
employeeId: '7',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1378,
salary: 15890
}
},
employees: []
},
]
},
]
},
{
employee: 'Ned',
employeeId: '2',
roleDetails: {
title: 'CMO',
compensation: {
bonus: 18293,
salary: 47291
}
},
employees: [
{
employee: 'Trent',
employeeId: '8',
roleDetails: {
title: 'Marketing Manager',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [
{
employee: 'Harry',
employeeId: '9',
roleDetails: {
title: 'Marketing Associate',
compensation: {
bonus: 18492,
salary: 188929
}
},
employees: []
}
]
}
]
},
{
employee: 'Elsa',
employeeId: '3',
roleDetails: {
title: 'CFO',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [
{
employee: 'Harry',
employeeId: '10',
roleDetails: {
title: 'Finance Associate',
compensation: {
bonus: 14829,
salary: 1492002
}
},
employees: []
}
]
}]
Let's imagine we take a snapshot of this company once and then again 3 months later. In between there, some employees have been added or removed, some have had salary increases or job title changes, and some have changed roles so they now report to different people.
How would I create a diff that can accurately identify these changes to summarize to users in a human readable way? I tried a basic text diff like this: http://jsfiddle.net/cs5d3uwn/ but it doesn't recognize that two employees with the same ID are the same, and that ID never changes. So if one employee replaces the other at the same position, it reports that some of the attributes of that employee changed, not that it's a remove and add.
The ideal output would be something I could use to summarize the differences in words, like this:
changes: [
{ employeeId: 10, name: "Lisa", path: "employees[0].employees[2].employees[0]", change: 'ADDED' }
{ employeeId: 6, name: "Tom", path: "employees[0].employees[1].employees[0]", change: 'REMOVED' }
{ employeeId: 4, name: "Ned", path: "employees[1]", change: 'UPDATED', key: 'salary', oldValue: 47291, newValue: 89399 },
{ employeeId: 7, name: "Harry", change: 'MOVED', oldPath: 'employees[1].employees[0].employees[0]', newPath: 'employees[1].employees[1]'}
{ employeeId: 7, name: "Harry", change: 'UPDATED', path: 'employees[1].employees[1].roleDetails.title', oldValue: 'Marketing Associate', newValue: 'Marketing Manager' }]
Any pointers on libraries to use or approaches to tackle the problem would be very appreciated.
The nested structure can be flattened without any loss of information by giving each employee a reportsTo property. This contains as much information as the "lineage" that the OP suggests.
Since reportsTo has a simple scalar value (the id of the employee this employee reports to), it's change over time can be represented just like a change to any other employee prop.
Another advantage is concision in what constitutes a change. If an employee's boss's boss's boss changes, that's a change in their lineage, but not really a change from an HR perspective (I would assert). That employee still reports to their same boss.
let flatArray = [];
function transformEmployee(employee, reportsTo) {
let result = Object.assign({}, employee);
delete result.employees;
result.reportsTo = reportsTo ? reportsTo.employeeId : null;
flatArray.push(result);
}
// invoke fn on every employee in the tree, depth-first
function traverse(employee, reportsTo, fn) {
if (employee.employeeId) fn(employee, reportsTo);
employee.employees.forEach(e => traverse(e, employee, fn));
}
const employee = getData();
traverse(employee, null, transformEmployee)
console.log(flatArray)
function getData() {
return {
employees: [{
employee: 'John',
employeeId: '1',
roleDetails: {
title: 'CEO',
compensation: {
bonus: 10000,
salary: 899999
}
},
employees: [{
employee: 'Will',
employeeId: '4',
roleDetails: {
title: 'Assistant to CEO',
compensation: {
bonus: 9919,
salary: 17728
}
},
employees: []
},
{
employee: 'Jane',
employeeId: '5',
roleDetails: {
title: 'Head of Operations',
compensation: {
bonus: 8190,
salary: 17492
}
},
employees: [{
employee: 'Tom',
employeeId: '6',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1839,
salary: 18429
}
},
employees: []
},
{
employee: 'Patricia',
employeeId: '7',
roleDetails: {
title: 'Operations Specialist',
compensation: {
bonus: 1378,
salary: 15890
}
},
employees: []
},
]
},
]
},
{
employee: 'Ned',
employeeId: '2',
roleDetails: {
title: 'CMO',
compensation: {
bonus: 18293,
salary: 47291
}
},
employees: [{
employee: 'Trent',
employeeId: '8',
roleDetails: {
title: 'Marketing Manager',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [{
employee: 'Harry',
employeeId: '9',
roleDetails: {
title: 'Marketing Associate',
compensation: {
bonus: 18492,
salary: 188929
}
},
employees: []
}
]
}
]
},
{
employee: 'Elsa',
employeeId: '3',
roleDetails: {
title: 'CFO',
compensation: {
bonus: 10000,
salary: 129999
}
},
employees: [{
employee: 'Harry',
employeeId: '10',
roleDetails: {
title: 'Finance Associate',
compensation: {
bonus: 14829,
salary: 1492002
}
},
employees: []
}]
}
]
}
}
With that, we're ready to record differences between two arrays. We can produce three arrays: adds, drops, and diffs
adds and drops are straight-forward enough...
const oldEmployees = [ /* ... */];
const newEmployees = [ /* ... */];
// adds are employees in the new array not in the old array
const adds = newEmployees.filter(newE =>
!oldEmployees.find(oldE => oldE.employeeId === newE.employeeId));
// drops are employees in the old array not in the new array
const drops = oldEmployees.filter(newE =>
!newEmployees.find(oldE => oldE.employeeId === newE.employeeId));
That leaves diffs, which are employees (matched by ids) in both arrays but have had one or more value change. Here's a working demonstration of how to compare two objects with a fixed set of keys that are known a priori...
// compare two versions of an employee (with the same ids)
// create a diff object that describes differences
// this presumes a fixed set of keys, as the OP has
function compare(id, newE, oldE, diffs) {
const keyPaths = [['employee'], ['reportsTo'], ['roleDetails', 'title'], ['roleDetails', 'compensation', 'salary'], ['roleDetails', 'compensation', 'bonus']];
keyPaths.forEach(key => {
let newValue = valueAtPath(newE, key);
let oldValue = valueAtPath(oldE, key);
if (newValue !== oldValue) {
diffs.push({ id, key: key.join('.'), oldValue, newValue });
}
});
}
// get a value at a path in an object
function valueAtPath(object, path) {
if (path.length === 1) return object[path[0]];
return valueAtPath(object[path[0]], path.slice(1))
}
let oldElsa = {
employee: 'Elsa',
employeeId: '3',
reportsTo: '12',
roleDetails: {
title: 'Bookkeepper',
compensation: {
bonus: 1000,
salary: 60000
}
}
}
let newElsa = {
employee: 'Elsa',
employeeId: '3',
reportsTo: '2',
roleDetails: {
title: 'CFO',
compensation: {
bonus: 10000,
salary: 129999
}
}
}
let diffs = []
compare(3, newElsa, oldElsa, diffs);
console.log(diffs)
Given our old and new employee sets, we'd just run this diff process on all of them...
const oldEmployees = [ /* ... */];
const newEmployees = [ /* ... */];
let diffs = [];
newEmployees.forEach(newE => {
const id = newE.employeeId;
const oldE = oldEmployees.find(o => o.employeeId === id));
compare(id, newE, oldE, diffs);
});
i need to concat all the 'externalId'(inside prod obj) + "id" (inside sup array) + "name" (inside product obj). What would be the best way to do that? I've tried with map and reduce but I wasn't successful. Any help will be appreciated.
const jsonResultKeys = ['AAA', 'BBB', 'CCC']
const items = [];
jsonResultKeys.forEach(k => {
const item = Jsonresult.items[k];
items.push({
description: item.product.name + ':' + item.product.sup[0] + ':'+ item.product.sup[0].prod.externalId ,
})
});
the output expected for this example:
[
{ description: '4444:2:product1'},
{ description: '3333:2:product2'},
{ description: '2222:1:product3'}
]
the json object:
const Jsonresult = {
items: {
'AAA': {
createdAt: '2021-02-11T17:25:22.960-03:00',
product: {
sup: [{
prod: {
externalId: **4444**
},
id: **2**
}],
name: "**product 1**"
},
total: 9.84,
quantity: 1,
price: 15,
updatedAt: '2021-02-11T17:25:22.960-03:00'
},
'BBB': {
createdAt: '2021-02-11T17:25:22.960-03:00',
product: {
sup: [{
prod: {
externalId: **3333**
},
id: **2**
}],
name: "**product 2**"
},
total: 9.84,
quantity: 1,
price: 15,
updatedAt: '2021-02-11T17:25:22.960-03:00'
},
'CCC': {
createdAt: '2021-02-11T17:25:22.960-03:00',
product: {
sup: [{
prod: {
externalId: **2222**
},
id: **1**
}],
name: "**product 3**"
},
}
},
}
The Array#map() method is the most logical method to use - see #MichaelMano's solution - but if you have to use .push() to populate items (const) then stick with .forEach() as follows:
Object.values( Jsonresult.items ).forEach(item => {
items.push( {description: `${item.product.sup[0].prod.externalId}:${item.product.sup[0].id}:${item.product.name}`} );
});
DEMO
const items = [];
const Jsonresult = {
items: {
'AAA': {
createdAt: '2021-02-11T17:25:22.960-03:00',
product: {
sup: [{
prod: {
externalId: 4444
},
id: 2
}],
name: "product 1"
},
total: 9.84,
quantity: 1,
price: 15,
updatedAt: '2021-02-11T17:25:22.960-03:00'
},
'BBB': {
createdAt: '2021-02-11T17:25:22.960-03:00',
product: {
sup: [{
prod: {
externalId: 3333
},
id: 2
}],
name: "product 2"
},
total: 9.84,
quantity: 1,
price: 15,
updatedAt: '2021-02-11T17:25:22.960-03:00'
},
'CCC': {
createdAt: '2021-02-11T17:25:22.960-03:00',
product: {
sup: [{
prod: {
externalId: 2222
},
id: 1
}],
name: "product 3"
},
}
},
};
Object.values( Jsonresult.items ).forEach(item => {
items.push( {description: `${item.product.sup[0].prod.externalId}:${item.product.sup[0].id}:${item.product.name}`} );
});
console.log( items );
You could do the following, Map over the results and return an object, this will create an array of objects.
You wont even need the keys.
const map = Object.values(Jsonresult.items).map((item) => {
return {
description: `${item.product.sup[0].prod.externalId}:${item.product.sup[0].id}:${item.product.name}`,
};
});
[
{ description: '4444:2:product 1' },
{ description: '3333:2:product 2' },
{ description: '2222:1:product 3' }
]
I have an array of objects, each containing a path property which holds the value of "paths" to which I'd like to map the array elements to.
let myData = [
{
path: ['Movies', 'Comedies', 'TopRanked'],
name: 'The Hangover',
id: '1',
},
{
path: ['Movies', 'Comedies', 'TopRanked'],
name: 'Eurotrip',
id: '2',
},
{
path: ['Movies', 'Action'],
name: 'Need for Speed',
id: '3',
},
{
path: ['Life'],
name: 'Not so bad',
id: '4',
},
{
path: ['Life', 'Financial', 'Income'],
name: 'Making Hundreds',
id: '5',
},
{
path: ['Life', 'Financial', 'Income'],
name: 'Making Thousands',
id: '6',
},
{
path: ['Life', 'MonthlySpent'],
name: 'Just a little bit',
id: '7',
},
{
path: ['Life', 'MonthlySpent'],
name: 'Living large',
id: '8',
},
];
console.log(myData);
Essentially, the result I am looking for is a breakdown of that array into as many as nested arrays as needed (relative to all possible available paths), with each retaining its "type" - either a parent or an item. So the desired output is like so:
let myTree = [
{
name: 'Movies',
type: 'parent',
children: [
{
name: 'Comedies',
type: 'parent',
children: [
{
name: 'TopRanked',
type: 'parent',
children: [
{
name: 'The Hangover',
type: 'item',
id: 1,
path: ['Movies', 'Comedies', 'TopRanked']
},
{
name: 'Eurotrip',
type: 'item',
id: 2,
path: ['Movies', 'Comedies', 'TopRanked'],
}
]
},
]
},
{
name: 'Action',
type: 'parent',
children: [
{
name: 'Need for Speed',
type: 'item',
id: 3,
path: ['Movies', 'Action'],
},
]
}
]
},
{
name: 'Life',
type: 'parent',
children: [
{
name: 'Not so bad',
type: 'item',
id: 4,
path: ['Life'],
},
{
name: 'Financial',
type: 'parent',
children: [
{
name: 'Income',
type: 'parent',
children: [
{
name: 'Making Hundreds',
type: 'item',
id: 5,
path: ['Life', 'Financial', 'Income'],
},
{
name: 'Making Thousands',
type: 'item',
id: 6,
path: ['Life', 'Financial', 'Income'],
}
]
}
]
},
{
name: 'MonthlySpent',
type: 'parent',
children: [
{
name: 'Just a little bit',
type: 'item',
id: 7,
path: ['Life', 'MonthlySpent'],
},
{
name: 'Living Large',
type: 'item',
id: 8,
path: ['Life', 'MonthlySpent'],
}
]
}
]
}
]
console.log(myTree);
I tried the following, and while the tree structure is created, the "item"-types are not placed as the array-value of the last nested "parent" type:
function treeData(data) {
var result = [],
hash = { _: { children: result } };
data.forEach(function (object) {
object.path.reduce(function (o, p) {
if (!o[p]) {
o[p] = { _: { name: p, children: [] } };
o._.children.push(o[p]._);
}
return o[p];
}, hash)._.name = object.name;
});
return result;
}
Would appreciate a working solution, as I am wracking my head and can't find one. Tnnx.
The approach below follows a similar pattern to your code i.e. loop every object, but instead of a reduce simply loops every item in path and creates a branch off the root. When there are no more 'branches' then add the original object. See the comments.
let myData = data();
let myTree = treeData(data);
console.log(myTree);
function treeData(data) {
let root = {"children": []} // create origin
for (obj of myData) { // loop items in the data
obj.type = "Item"; // add a property to suit your output
let tree = root; // start at root every object
for (path of obj.path) { // loop over items in path
let branch = tree.children.find(k => k.name == path); // look for branch
if (!branch) { // if no branch, create one
branch = {"name": path, "type": "parent", "children": []}
tree.children.push(branch); // push this into children of current level
}
tree = branch; // set tree to branch before processing next item in path
}
tree.children.push(obj); // add the item to the hierarchy after path is exhausted
}
return root.children; // return children of the root to suit your output
}
function data() {
return [
{
path: ['Movies', 'Comedies', 'TopRanked'],
name: 'The Hangover',
id: '1',
},
{
path: ['Movies', 'Comedies', 'TopRanked'],
name: 'Eurotrip',
id: '2',
},
{
path: ['Movies', 'Action'],
name: 'Need for Speed',
id: '3',
},
{
path: ['Life'],
name: 'Not so bad',
id: '4',
},
{
path: ['Life', 'Financial', 'Income'],
name: 'Making Hundreds',
id: '5',
},
{
path: ['Life', 'Financial', 'Income'],
name: 'Making Thousands',
id: '6',
},
{
path: ['Life', 'MonthlySpent'],
name: 'Just a little bit',
id: '7',
},
{
path: ['Life', 'MonthlySpent'],
name: 'Living large',
id: '8',
},
];
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
How to get Values of opts in a String with MongoDB regex?
I want to search cats name And get cats opts with regex
Schema:
const childSchema = new Schema({
type: String,
id: { type: Number, required: true, unique: true },
title: String,
message_text: String,
parse_mode: String,
thumb_url: String,
description: String,
});
const parentSchema = new Schema({
_id: Number,
name: String,
opts: childSchema,
});
Code:
Mq.aggregate(
[
{
"$match": {
"name": { "$regex": "c", "$options": "i" }
}
},
{ "$unwind": "$name" },
{
"$match": {
"name": { "$regex": "c", "$options": "i" }
}
},
{
"$group": {
"_id": "$opts",
}
}
],
function (err, results) {
if (err) {
console.log(err)
} else {
console.log(results)
}
}
)
Output:
[ { _id:
{ type: 'article',
id: 2,
title: 'persian cat',
message_text: 'test',
parse_mode: 'Markdown',
thumb_url: 'http://www.immig-chicago.com/clientuploads/graphics/dvLottery_2a.jpg',
description: 'des',
_id: 5a011c3236bdcc2540747d0f } },
{ _id:
{ type: 'article',
id: 1,
title: 'cat',
message_text: 'Hi',
parse_mode: 'Markdown',
thumb_url: 'http://www.immig-chicago.com/clientuploads/graphics/dvLottery_2a.jpg',
description: 'des',
_id: 59f7cf23ba668128fc48b8a7 } } ]
But I need values inside of opts in output, I Mean Something like This:
{ type: 'article',
id: 2,
title: 'persian cat',
message_text: 'test',
parse_mode: 'Markdown',
thumb_url: 'http://www.immig-chicago.com/clientuploads/graphics/dvLottery_2a.jpg',
description: 'des',
_id: 5a011c3236bdcc2540747d0f },
{ type: 'article',
id: 1,
title: 'cat',
message_text: 'Hi',
parse_mode: 'Markdown',
thumb_url: 'http://www.immig-chicago.com/clientuploads/graphics/dvLottery_2a.jpg',
description: 'des',
_id: 59f7cf23ba668128fc48b8a7 }
Update:
I have let opts = []; in my Project and I want to remove the key and just get values of opts and put them in let opts - [{},{},{},....]
My Data:
[ [ { _id: 0, name: 'dog', opts: [Object], __v: 0 },
{ _id: 1, name: 'cat', opts: [Object], __v: 0 },
{ _id: 2, name: 'persian cat', opts: [Object], __v: 0 } ] ]
I know one thing for sure You can use $project on you Mq.aggregate to hide the _id on the final result by assigning the value like this: { _id: 0 }.
I also found this that might help ;)
Solved ✔️
1: I Finded My Cats name with regex
2: I Got Cats opts value By .distinct()
var regex = new RegExp("c", "i"); //Case insensitive Match
Mq.find().distinct('opts', {name: regex}, function(err, docs) {
console.log(docs)
})
Output:
[{ type: 'article',
id: 1,
title: 'cat',
message_text: 'Hi',
parse_mode: 'Markdown',
thumb_url: 'http://www.immig-chicago.com/clientuploads/graphics/dvLottery_2a.jpg',
description: 'des',
_id: 59f7cf23ba668128fc48b8a7 },
{ type: 'article',
id: 2,
title: 'persian cat',
message_text: 'test',
parse_mode: 'Markdown',
thumb_url: 'http://www.immig-chicago.com/clientuploads/graphics/dvLottery_2a.jpg',
description: 'des',
_id: 5a011c3236bdcc2540747d0f } ]