Is there a way to update items in an array with JsonPatch? - javascript

The API to be invoked uses JsonPatch. The following is a sample JSON.
{ "hello": false
, "array1":
[ { "subarray": [ "k2", "k1"] }
, { "subarray": [ "k1"] }
]
}
I would like to update both the subarrays (elements of the array1). There could be N number of elements/items in array1 that I'm not aware of when calling this API.
Now I can do the following if I am aware of the the size of array1.
[{ "op": "add", "path": "/array1/0/subarray/0", "value": "gk" }]
[{ "op": "add", "path": "/array1/1/subarray/0", "value": "gk" }]
But since I'm not aware of the the size of array1, it does not seem that this can be achieved using JsonPointer. Is there something that can be done to do an update that targets all the elements of array1 (i.e all the subarrays) in one go? Something like this:
[{ "op": "add", "path": "/array1/*/subarray1/0", "value": "gk-new" }]
After invocation, the resulting subarrays should have an additional element "gk-new" in addition to what they have?

There is no wildcard support in JsonPatch or JsonPointer. Therefore, what is asked in the question is not possible.

Related

check if item exists in json file then get it if exists. And if not complete executing the code

I get a json file from outer link by ajax call. i want to check element is exists in this json file or not and get it if exists. because it changes every time and items increases or decreases. If I get item and this item not existing, I get error and the code not complete. i want to check this item json.children[1].children and json.children[2].children ,..... if exists.
{
"num": 1,
"name": "aa",
"properites": [
{
"name": "prop1",
"value": "value1"
}
],
"children": [
{
"num2": 1,
"name2": "name2",
"properites": [
{
"name": "name",
"value": "value"
}
],
"children": []
},
{
"name": 1,
"num": "1",
"attributes": [
{
"name": "name",
"value": "value"
}
],
"children": []
.......................... big json file
I have tried to get these Items and set in local storage to use in table by this:
localStorage.setItem("row1-item1", json.children[1].children);
localStorage.setItem("row1-item2", json.children[2].children);
localStorage.setItem("row1-item3", json.children[3].children);
localStorage.setItem("row1-item4", json.children[4].children);
localStorage.setItem("row2-item1", json.name[1].children);
localStorage.setItem("row2-item2", json.name[2].children);
localStorage.setItem("row2-item3", json.name[3].children);
localStorage.setItem("row2-item4", json.name[4].children);
the problem here is if json.children[4].children not existing the code not complete the next line and jump out of ajax call even if json.name[1].children is exists. I tried try/catch but not solved it
Try to use map
json.children.map((children,index)=>{
localStorage.setItem('row${index}-item${index}`, children);
}
Or you can use forEach or for loop instead of map.

JSON list optimization

I want to create a JSON API that returns a list of objects. Each object has an id, a name and some other information. API is consumed using JavaScript.
The natural options for my JSON output seems to be:
"myList": [
{
"id": 1,
"name": "object1",
"details": {}
},
{
"id": 2,
"name": "object2",
"details": {}
},
{
"id": 3,
"name": "object3",
"details": {}
},
]
Now let's imagine that I use my API to get all the objects but want to first do something with id2 then something else with id1 and id3.
Then I may be interested to be able to directly get the object for a specific id:
"myList": {
"1": {
"name": "object1",
"details": {}
},
"2": {
"name": "object2",
"details": {}
},
"3": {
"name": "object3",
"details": {}
},
}
This second option may be less natural when somewhere else in the code I want to simply loop through all the elements.
Is there a good practice for these use cases when the API is used for both looping through all elements and sometime using specific elements only (without doing a dedicated call for each element)?
In your example you've changed the ID value from 1 to id1. This would make operating on the data a bit annoying, because you have to add and remove id all the time.
If you didn't do that, and you were relying on the sorted order of the object, you may be in for a surprise, depending on JS engine:
var source = JSON.stringify({z: "first", a: "second", 0: "third"});
var parsed = JSON.parse(source);
console.log(Object.keys(parsed));
// ["0", "z", "a"]
My experience is to work with arrays on the transport layer and index the data (i.e. convert array to map) when required.

Indexing array values in an object in an IndexedDB

For a Chrome app, wich stores data in IndexedDB, i have a object like this:
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"parcels": [
{
"service": "DHL",
"track": "12345"
},
{
"service": "UPS",
"track": "3254231514"
}
]
}
If i store the hole object in an objectStore, can i use an index for "track", which can be contained multiple times in each order object?
Or is it needed or possibly better/faster to split each object into multiple objectStores like know from relational DBs:
order
orderitem
parcel
The solution should also work in a fast way with 100.000 or more objects stored.
Answering my own question: I have made some tests now. It looks like it is not possible to do this with that object in only 1 objectStore.
An other example object which would work:
var myObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"shipping": {"method": "letter",
"company": "Deutsche Post AG" }
}
Creating an index will be done by:
objectStore.createIndex(objectIndexName, objectKeypath, optionalObjectParameters);
With setting objectKeypath it is possible to address a value in the main object like "name":
objectStore.createIndex("name", "name", {unique: false});
It would also be possible to address a value form a subobject of an object like "shipping.method":
objectStore.createIndex("shipping", "shipping.method", {unique: false});
BUT it is not possible to address values like the ones of "track", which are contained in objects, stored in an array. Even something like "parcels[0].track" to get the first value as index does not work.
Anyhow, it would be possible to index all simple elements of an array (but not objects).
So the following more simple structure would allow to create an index entry for each parcelnumber in the array "trackingNumbers":
var simplifiedOrderObject = {
"ordernumber": "123-12345-234",
"name": "Mr. Sample",
"address": "Foostreet 12, 12345 Bar York",
"orderitems": [
{
"item": "brush",
"price": "2.00"
},
{
"item": "phone",
"price": "30.90"
}
],
"trackingNumbers": ["12345", "3254231514"]
}
when creating the index with multiEntry set to true:
objectStore.createIndex("tracking", "trackingNumbers", {unique: false, multiEntry: true});
Anyhow, the missing of the possibility to index object values in arrays, makes using indexedDB really unneeded complicated. It's a failure in design. This forces the developer to do things like in relational DBs, while lacking all the possibilities of SQL. Really bad :(

How to form mongoose query for $all in array

Given this collection:
[{
"users": [{
"name": "one"
}, {
"name": "two"
}]
}, {
"users": [{
"name": "one"
}, {
"name": "three"
}]
}, {
"users": [{
"name": "fifteen"
}, {
"name": "one"
}]
}]
How can I query this using values (ie, "one" and "two") so that the findOne method returns only the document that has both "name":"one"and "name":"two" (order not relevant)? The users array will always have 2 elements, no more, no less.
I was trying something along the lines of:
Collection.findOne({"users":{$all:["one", "two"]}})
But it isn't working. Can anyone help?
EDIT: Latest attempt:
Collection.findOne({"users":{"name": {$all:["one","two"]}}})
Try this one:
{"users": {$all: [{"name": "one"}, {"name": "two"}]}}
Or use dot notation as proposed by JohnnyHK.
See here how $all is used: https://docs.mongodb.org/manual/reference/operator/query/all/
EDIT: Data was changed.
You can do this by using dot notation to identify a specific field within the array to which the $all operator should be applied:
Collection.findOne({'users.name': {$all: ['one', 'two']}})

Javascript looping through elements and adding to table

I'm having trouble finding a solution that will help me loop through a bunch of elements and putting the chosen values into a table. I've been able to withdraw some values but the method isn't dynamic.
Here is an example:
var Table = {
"credit": {
"link": "site link",
"logoUrl": "logo url",
"message": "message"
},
"groups": [
{
"labels": [
{
"name": "Western Conference",
"type": "conference"
},
{
"name": "Central Division",
"type": "division"
}
],
"standings": [
{
"stats": [
{
"name": "gp",
"value": 20
},
{
"name": "w",
"value": 17
},
{
"name": "l",
"value": 0
},
{
"name": "gf",
"value": 64
},
{
"name": "ga",
"value": 37
},
{
"name": "gd",
"value": 27
},
{
"name": "pts",
"value": 37
}
],
"team": {
"id": 12345,
"link": "team link",
"name": "team name",
"shortName": "team"
}
},
This is the structure of the elements. So far I've used this:
document.getElementById("sGamesPlayed").innerHTML=Table.groups[0].standings[0].stats[0].value;
to withdraw values. However there are more teams, stats and divisions so I would need some kind of loop to go through the elements and put the into a dynamic table.
I would consider you to look at http://underscorejs.org/.
it provides a bunch of utility functions that could help you,
for example, _.each() helps you loop through JSON properties.
for the sample objects you've given (after completing the missing brackets at the end),
_.each(Table.groups[0].standings[0].stats, function(stats){
console.log(stats['name']+","+stats['value'])
})
gives me:
gp,20
w,17
l,0
gf,64
ga,37
gd,27
pts,37
how it works is that you provide the object you want as the first argument and the function that you give as the second argument will be called with each element of the first argument (Assuming it is a list).
I would also urge you to look at underscore templating that you can use to render your table where i put the console.log :
http://net.tutsplus.com/tutorials/javascript-ajax/getting-cozy-with-underscore-js/
http://scriptble.com/2011/01/28/underscore-js-templates/
I guess your question is about filtering the values of the array standings. In order to do that you can use the jQuery grep function (if you want to use jQuery).
For example you can write:
var arr = $.grep(Table.groups[0].standings[0].stats, function(d){return d.value>25})
Which will give
arr = [{"name": "gf","value": 64}, {"name": "ga", "value": 37},{"name": "gd", "value": 27},{"name": "pts", "value": 37}]
If this is not what you meant, can you please create a jsFiddle with a sample of what you want?
Depending on what you want to do with the results, you can go over the object using a scheme like:
var groups, standings, stats, value;
groups = Table.groups;
// Do stuff with groups
for (var i=0, iLen=groups.length; i<iLen; i++) {
standings = groups[i].standings;
// Do stuff with standings
for (var j=0, jLen=standings.length; j<jLen; j++) {
stats = standings[j];
// Do stuff with stats
for (var k=0, kLen=stats.length; k<kLen; k++) {
value = stats[k].value;
// Do stuff with value
}
}
}
Of course I have no idea what the data is for, what the overall structure is or how you want to present it. But if you have deeply nested data, all you can do is dig into it. You might be able to write a recursive function, but it might also become very difficult to maintain if the data structure is complex.

Categories

Resources