I'm starting with this JSON-LD document (json-ld playground), where the meat looks like this:
"from": [
"protein:15718680",
"protein:157427902"
],
"protein_gene": [
"gene:522311",
"gene:3702"
]
Now, the "protein_gene" predicate always takes gene identifiers as values. Since there can be hundreds of these, what I really want in the JSON is this:
"from": [
"protein:15718680",
"protein:157427902"
],
"protein_gene": [
"522311",
"3702"
]
without the "gene" prefix everywhere. Is it possible? The closest I got, based on this SO question, was this (json-ld playground). It causes the predicate values to be expanded into IRIs, and not relative IRIs, but those based on the #vocab. But it is not right, because I want a predicate-specific vocab.
I also know that I can play tricks with embedded (local) contexts, and I got this (json-ld playground) to work, but it is still uglier than I would like.
There are a couple of ways to do this for a single property, but not multiple (more than two, you can use #vocab and #base if you have two). Apart from injecting contexts, there's no way to scope #vocab and #base to a property.
Related
I use JSON Schema to describe my data structure
My data contains specific arrays of the following structure:
{
"string1",
"string2",
...
"stringN",
{
"object": "as",
"last": "item"
}
}
I'm wondering how to describe this in json schema (especially the thing "last item is an object")
If I knew the number of string items, "prefixItems" would do the thing (but there could be any number of them).
If the object was the first (not last) item, "prefixItems" together with "items" would work.
If is use "contains", it only checks the object is somewhere in my array, not checking it is the last item.
Seems that I need something like "reversePrefixItems", if such option existed - but it doesn't exists.
So, what is a proper way to describe the last item of an array? (and optionally all the preceding ones - knowing their type but not their total count)
there has been discussion of a proposed keyword postfixItems but it has not yet made it into the spec. I don't think there is a way to do this currently.
For this JSON API design problem, I have an arbitrary set of key-value pairs that need to be provided in the API Request/Response bodies. Both the keys and values are unknown. What is the best way to structure this?
As far as I can tell, there are two ways to accomplish this:
1. Undocumented object keys
{
"fruit": "Apple",
"sport": "Hockey",
...
"keyN": "valueN"
}
PROS: Very clean, easy for application logic to parse
CONS: This object can't be documented properly - the shape of the object is infinitely arbitrary.
2. Array of Objects
[
{
"key": "fruit",
"value": "Apple"
},
{
"key": "sport",
"value": "Hockey"
},
...
{
"key": "keyN",
"value": "valueN"
}
]
PROS: Easy to document and understand as an array of objects with a known structure.
CONS: Application logic will be more verbose.
What is the best way to structure this?
NOTE: This is a question about API documentation, not about application logic. As noted above, I'm well aware that #1 is the best solution for manipulation in code. But it's unclear to me just yet how to document this in API docs in such a way that will always be interpreted correctly
I very, very strongly recommend #1. #2 is a perversion. Your data structure is a dictionary. Don't use an array to implement a dictionary, but with half the features.
Think about it: You say you cannot document #1. So how are you going to document #2? If #1 mustn't contain a key "strawberry", how do you document that #2 mustn't contain a dictionary with a (key, value) pair of key = "key", value = "strawberry"?
How do you check whether #1 or #2 contains a key "fruit", and what the value is? #1 is a direct access. dict ["fruit"]. In #2 you need to iterate through the array elements, check that they are all dictionaries, check if there is one with an entry key: "fruit", check that it has another entry "value". Maybe if you are paid by lines of code you would do that.
Funny enough, three completely different answers, each with a downvote. Obviously at least two downvoters are stupid.
Personally I don't see much difference between #1 and #2 in terms of documentation. If the fields are unknown then an empty map/object vs an empty array doesn't really matter.
I've seen this referred to as a 'Json Junk Drawer'.
One addition I have seen is a named map/object specific for the 'Json Junk Drawer' like:
{
"fieldsThatDontChange" : "example",
"attributes" :{
"unknownfield" : "unknown"
}
}
It's all an anti-pattern really. But one small benefit here is you can tell clients that the attributes section is where to put their undocumented stuff. Maybe even enforce client specific schemas on the attributes section if that's a use-case for example.
Here is some more info on JSON junk drawers which has some links to youtube videos discussing the subject:
http://apievangelist.com/2015/01/21/rest-api-design-bridging-what-we-have-to-the-future-by-organizing-the-json-junk-drawer/
The better solution is:
2. Array of Objects
[
{
"key": "fruit",
"value": "Apple"
},
{
"key": "sport",
"value": "Hockey"
},
...
{
"key": "keyN",
"value": "valueN"
}
]
Arrays are exactly the correct pattern to use when there is arbitrary length involved. This is more verbose but easier to understand. Favour verbosity.
For ease of notation, I will use JSON in the following, though the anti-pattern can be programmed in many languages
Let's say that I have a sensible JSON such as
{
"SomeProperty": "SomeValue",
"SomeOtherProperty": 42,
"Items": [
"ValueOfItem0", "ValueOfItem1"
]
}
It has simple entries and an array of items. An alternative way of representing the data, which I think is an anti-pattern and for which I search the name is
{
"someProperty": "someValue",
"someOtherProperty": 42,
"Item0": "valueOfItem0",
"Item1": "valueOfItem1",
"NumberOfItems": 2
}
Instead of by the array, the items are kept 'together' by the keys, which a consumer of the anti-pattern JSON would need to predict. For this reason, the NumberOfItems property has been added, though by using a TryGet-like technique, the property can be made obsolete. Why would anyone do this? Limitations of the serializer.
Comments:
My search has revealed nothing. The sort-of opposite direction is the "Arrject", therefore my humble suggestion for the described anti-pattern, if yet unnamed, would be "Orray", a name already used by Star Wars.
I'm generating some JSON with XStream for an object that contains an ArrayList. I have the #XStreamImplicit annotation set for the specific field. When I have 2 elements in the array it converts to JSON properly...
"cap": [
"switch",
"switch2"
]
However if there is only one element in the array I get this...
"cap": "switch"
Therefore it's not showing up as an array (even though there is only one element in it). This makes it a challenge to deserialize it on the other end (which I do not have control of). What I want it to do is the following...
"cap": [
"switch"
]
I'm assuming this is some sort of automatic assumption made for efficiency sake in the library. Either in XStream or Jettison. However is there a way to force the array setting here?
I have a collection with records that look like this
{
"_id":{
"$oid":"4e3923963b123b59b73bde67"
},
"ident":"terrainHome",
"columns":[
[
"4e3fbe57dccd1a0cc47509ab",
"4e3fbe57dccd1a0cc47509ac"
],
[
]
]
}
each document can have two or three columns,
each column is an array of blocks, which are stored in a different collection,
I want a query that will return the ident for the document that contains a block.
I tried
db.things.find({ columns[0] : "4e3fbe57dccd1a0cc47509ac" });
but this didn't work
I'll keep trying. :)
You are mixing types here (ObjectId != String). You should always keep things as ObjectId not sometimes as strings, as you have in the array. This is probably not the root of your problem, but could be problematic later.
In you example you can do this:
db.things.find({ "columns.0" : "4e3fbe57dccd1a0cc47509ac" });
Generally arrays of arrays can be challenging to query on when they are more structured (like embedded docs).
If you don't care about WHERE the match is, try
db.things.find({'columns' : $in : ["4e3fbe57dccd1a0cc47509ac"] });
This works
db.things.find({"$where":"typeof(this.columns[0]) != \"undefined\" && this.columns[0].indexOf(\"4e48ed8245333bd40d000010\") != -1"});
I'll accept my own answer in a couple of days or so, unless someone can suggest a simpler solution.
Also here's a screen grab of the mongo console of the two suggested solutions that didn't work, (thanks though for taking the time), plus the complicated solution I've found that works. The screen grab demos that there are documents in the collection, the two suggested find commands, and the $where javascript solution showing that this works for first item in the array, second item in the array and returns no records for a non matching id.
I've tried dozens of variations of the suggested solutions, but they all turn up blank results.