RFC 7396 - JSON Merge Patch - Updating objects in a list - json

The RFC 7396 states:
If the patch is anything other than an object, the result will always be to replace the entire target with the entire patch. Also, it is not possible to patch part of a target that is not an object, such as to replace just some of the values in an array.
For example, if I have this document :
{
"id": 1,
"brand_name": "BMW",
"cars": [{
"id": 2,
"model": "S1",
"cost": 10000
}]
}
It is my understanding I can't partially update the car with the id #2 in order to update the cost for example:
{
"id": 1,
"cars": [{
"id": 2,
"cost": 20000
}]
}
(the idea here is to do not modify the model, just the cost. The ids are present just for the reconciliation)
Is that correct ?
If so, why couldn't we apply this algorithm to deal with lists:
Compare the actual representation of the car list with the patch representation:
If one item is missing in the patch representation => delete it
If one item has been added without reconciliation identifier => add it
If one item is present in both representations => modify it at the object level as a regular PATCH
Is that realistic ?

The way I read the the paragraph you sent, I would say.. no you are not able to do this. My understanding is that RFC 7396 is intended as a very simple no-fuss patch format.
If you want something with more features, consider using RFC 6902 instead.

Related

Updating JSON arrays in MarkLogic 9

I'm having trouble working out how to write a bit of XQuery. I have a JSON structure in MarkLogic that looks like:
{
"id": "pres003A10",
"title": "A Course About Something",
"description": "This course teaches people about some things they may not know.",
"author": "A.N. Author",
"updated": "2007-01-19",
"decks": [
{
"id":"really-basic-stuff",
"exclude": ["slide3", "slide12"]
},
{
"id":"cleverer-stuff",
"exclude": []
}
]
}
The exclude array contains the identifiers for slides in decks (presentations are made up of one or more decks of slides). I'm trying to write a piece of code that will look for a slide id in that exclude list and remove it if present or add it if not (a toggle).
I can obtain the array node itself using:
let $exclude := doc('/presentations/presentation.json')/object-node()/decks[id = 'markup-intro']/array-node('exclude')
but I can't for the life of me see how I then update that array to either remove an item or add it. The intention is call a function something like:
local:toggle-slide($presentation) as object-node()
{
(: xdmp:node-update(...) goes here :)
};
So, how do I update that array?
In memory JSON node trees (and XML trees, for that matter) are immutable.
The way to modify a tree is to construct a new tree, copying the nodes that haven't changed and creating the parent node and ancestor node with the changes.
That said, there's an easier way to modify JSON. If you call xdmp:from-json() on the root node, you will get a mutable in-memory map / array structure.
You can then navigate to the array using map:get() on the maps and [ITEM_NUMBER] on the arrays and delete or insert items FOR the appropriate json:array object.
When you're done, call xdmp:to-json() to turn the root map back into a node.
Hoping that helps,
If you need to update the json in the database, you can use xdmp:node-replace. The catch with node-replace is though, that you have to feed it with a named node. To do that, you need to wrap the array-node in an object-node, and then grab the array-node inside the object-node on the fly. Here a working example:
xquery version "1.0-ml";
(: insert test data :)
xdmp:document-insert("/presentations/presentation.json", xdmp:unquote('{
"id": "pres003A10",
"title": "A Course About Something",
"description": "This course teaches people about some things they may not know.",
"author": "A.N. Author",
"updated": "2007-01-19",
"decks": [
{
"id":"markup-intro",
"exclude": ["slide3", "slide12"]
},
{
"id":"cleverer-stuff",
"exclude": []
}
]
}'
))
;
(: node-replace array-node :)
let $exclude := doc('/presentations/presentation.json')/object-node()/decks[id = 'markup-intro']/array-node('exclude')
return xdmp:node-replace($exclude, object-node{
"exclude": array-node{ "other", "slides" }
}/node())
;
(: view if changed :)
doc('/presentations/presentation.json')
Note: consider looking at MarkLogic's Server-side JavaScript (SJS) support. Updating JSON might seem more natural that way, particularly if you need to make multiple changes in one go.
HTH!

getting the parent object from child object in nested objects from JSON with type script

Is it possible to get the parent object from a child object dynamically? Essentially, all I'm trying to accomplish is to dynamically retrieve the value of a property belonging to a child objects' parent. For example, in the following Json, I want to extract the driver of a particular car.:
{
"driver": [
{
"id": 1, |
"name": "Bob", |=> this is the parent
"age": "34", |
"car": [
{
"make": "BMW", |
"model": "3.20", | this is the child
"colour": "Silver",|
"mileage": [
{
"total": "350523",
"year": [
{
"2011": "3535",
"2012": "7852",
"2013": "8045"
}
],
"month": [
{
"december": "966",
"november": "546",
"october": "7657"
}
]
}
]
}
]
}
]
}
Using for loops:
for(let parent of data.driver) {
for(let car of parent.car) {
if(car.make === 'BMW') {
// can do what you like with 'parent'
}
}
}
Using filter() or find() (standard javascript):
drivers_who_drive_bwm = data.driver.filter((parent) => {
// find() will give -1, if no car was found that matched
// car.make === 'BWM'
return parent['car'].find((car) => car.make === 'BWM') !== -1
})
Also:
Your naming conventions are confusing. I would expect driver.car to be a single car, in your code it's array of cars. If it always contains single car, then it would be better not to use array. Same for .driver. Better key would be .drivers to indicate multiple drivers. (but maybe it is XML converted to json, in that case you are stuck with it?)
Whatever strategy you choose, you will basically be iterating through and returning. So I feel the "best" strategy is using what you are most comfortable with.
Typescript is just Javascript. So if you are comfortable with a Javascript-ey "functional programming" way of doing things you can use Array map & filter.
You of course will have to deal with application specific logic you have not specified like "What happens when the same make/model exists across different drivers?".
If you are not comfortable with functional programming you can always build up a series of maps and then perform lookups.
But if you need to get it right, always do what you are comfortable doing.
To answer this question, an Object reference is just a memory location. there is no concept of parents comes here. its may not have any parent (just a logical thinking as parent, so may not any other object have property having reference to it), or may a lot of object have referred to same memory location (i.e. multiple parent by your logic).
1> So Either you can put parent reference to each child element programitically. Note, here you cannot do by parsing a JSON string, because its contains only JSON data, not reference as parse-able.
2> Or else Try to find out the driver object (i.e. parent object) having child object which contains your value according to your condition. you ca use filter , map of array functions in javascript to do so. but whatever you are doing is just iterating and find. in that case underscrore js will be a good library to use

Microsoft Academic API, Knowledge graph search -- ReferenceIDs always empty

I'm using the graph search method of the Microsoft Academic API to retrieve citation IDs and reference IDs for a paper. However, while retrieving citation IDs works, the reference IDs field is always empty, even for papers which should have linked references. For example, retrieving this publication through the API:
POST https://westus.api.cognitive.microsoft.com/academic/v1.0/graph/search?mode=json
Content-Type: application/json
Host: westus.api.cognitive.microsoft.com
Ocp-Apim-Subscription-Key: my-api-key
{
"path": "/paper",
"paper": {
"select": [
"OriginalTitle",
"CitationIDs",
"ReferenceIDs"
],
"type": "Paper",
"id": [2059999322]
}
}
yields this response (I shortened the CitationIDs list for the sake of legibility):
{
"Results": [
[
{
"CellID": 2059999322,
"CitationIDs": "[630584464,2053566310,2239657960,...]",
"OriginalTitle": "Biodistribution of colloidal gold nanoparticles after intravenous administration: Effect of particle size",
"ReferenceIDs": ""
}
]
]
}
One thing I've noticed is that the graph schema provided here (at the bottom of the page) doesn't match the schema shown here (some of the attributes were renamed, e.g. NormalizedPaperTitle -> NormalizedTitle), so I thought the field was perhaps renamed to something else.
What is the correct query to get reference IDs through the API?
It should be ReferencesIDs, not ReferenceIDs

Mongo DB query of complex json structure

Say I have a json structure like so:
{
"A":{
"name":"dog",
"foo":"bar",
"array":[
{"name":"one"},
{"name":"two"}
]
},
"B":{
"name":"cat",
"foo":"bar",
"array":[
{"name":"one"},
{"name":"three"}
]
}
}
I want to be able to do two things.
1: Query for any "name":* within "A.array".
2: Query for any "name":"one" within "*.array".
That is, any object within a specific document's array, and any specific object within any document's array.
I hope I have used proper terminology here, I am just starting to familiarize myself with a lot of these concepts. I have tried searching for an answer but am having trouble finding something like my case.
Thanks.
EDIT:
Since I still haven't really made progress towards this, I'll just explain what I'm trying to do: I want to use the "AllSets" dataset (after I trim it down below 16mb) available on mtgjson.com. I am having problems getting mongo to play nicely though.
In an effort to try and learn what's going on, I have downloaded one set: http://mtgjson.com/json/OGW.json.
Here is a photo of its structure laid out:
I am unable to even get mongo to return an object from within the cards array using:
"find({cards: {$elemMatch: {name:"Deceiver of Form"}}})"
"find({"cards.name":"Deceiver of Form"})"
When I run either of the commands above it just returns the entire document to me.
You could use the positional projection $ operator to limit the contents of an array. For example, if you have a single document like below:
{
"block": "Battle for Zendikar",
"booster": "...",
"translations": "...",
"cards": [
{
"name": "Deceiver of Form",
"power": "8"
},
{
"name": "Eldrazi Mimic",
"power": "2"
},
{
"name": "Kozilek, the Great Distortion",
"power": "12"
}
]
}
You can query for a card name matching "Deceiver of Form", and limit fields to return only the matching array card element(s) using:
> db.collection.find({"cards.name":"Deceiver of Form"}, {"cards.$":1})
{
"_id": ObjectId("..."),
"cards": [
{
"name": "Deceiver of Form",
"power": "8"
}
]
}
Having said the above, I think you should re-consider your data model. MongoDB is a document-oriented database. A record in MongoDB is a document, so having a single record in a database does not bring out the potential of the database i.e. similar to storing all data in a single row in a table.
You should try storing the 'cards' into a collection instead. Where each document is a single card, (depending on your use case) you could add a reference to another collection containing the deck information. i.e: block, type, releaseDate, etc. For example:
// a document in cards collection:
{
"name": "Deceiver of Form",
"power": "8",
"deck_id": 1
}
// a document in decks collection:
{
"deck_id": 1,
"releaseDate": "2016-01-22",
"type": "expansion"
}
For different types of data model designs and examples, please see Data Model Design.

Displaying empty parameters in JSON

I'm building my first API which outputs in JSON, and was wondering: If one of the parameters is empty, is it best to still include that parameter name with an empty value, or not include it at all? For example, if a certain product has batteries it would normally output
"batteries": [
{
"device": "Vehicle",
"number": "4",
"type": "AA",
"included": "Not Included"
},
{
"device": "Remote",
"number": "2",
"type": "AAA",
"included": "Not Included"
}
],
If there are no remote batteries, should I just not include that second section? What if there aren't batteries at all, should I remove the whole battery node?
From the perspective of the json interpreter it won't matter. You should send the JSON however you want the consumer to reconstruct your objects...
Do you want the consumer to have a "Remote" object indicating there are no batteries?
Your example doesn't look like an empty node to me, it looks like meaningful data!
For actually empty nodes it may only matter if you need to keep the serialized object as small as possible (for whatever reason) or if you need to have something else besides JSON look at the serialized object later.
In my personal opinion from an API I like to see all meaningful nodes populated because it gives me an idea of the possibilities of the API.... "Oh, I see, so some of them have remotes and include batteries and this API can tell me that!"
In Javascript, you can treat an absent property in almost the same way you would trean a property set to null:
> a_unset = {}
> a_null = {a: null}
> a_null.a == a_unset.a
true
> a_null.a ? 1 : 0
0
> a_unset.a ? 1 : 0
0
Therefore in JSON, which is based on Javascript and most often consumed by Javascript code, it is customary to omit empty values.
But this is not a hard rule. JSON does provide the null value, so if you think your client code or target users would need to know that a property is there but unset, null might be a good choice. Otherwise just omit it, you will save space.