How to describe the predicate/edge of a triple in JSON-LD? - json-ld

I am new to JSON-LD and LOD so please excuse my use of terminology. I am working on creating a data model in JSON-LD to describe aggregated digital collections based on the European Data Model (http://pro.europeana.eu/edm-documentation).
I would like to create an #context area that describes the relationship:
ore:Aggregation --- edm:aggregatedCHO --> edm:ProvidedCHO
(where 'edm:aggregatedCHO' is the predicate/edge), but I would like to label edm:ProvidedCHO as 'sourceResource' in my model.
Currently my #context looks something like this:
{
"#context": {
"edm" : "http://www.europeana.eu/schemas/edm/",
"sourceResource" : {
"#id" : "edm:ProvidedCHO",
"#type" : "edm:aggregatedCHO"
}
}
}
My intention was to define the predicate ('edge') using #type, and the node contents using #id, but after reviewing the W3C Recommendation, this seems incorrect, and that 'edm:ProvidedCHO' should actually be the #type, because it describes the content type of the node (http://www.w3.org/TR/json-ld/#typed-values).
My question, generally, is where/how do you include the predicate of a triple in a JSON-LD #context statement?
In this case specifically, how do I represent a node called 'sourceResource' that contains edm:ProvidedCHO objects that are each an edm:aggregatedCHO?

Note that setting #type in the context says that the term is expected to be a literal with that datatype; you probably want to use this #type in the body, which will create a type edge, if you will.
Note that the #context does not define relationships, but terms, and how the values of the terms should be interpreted (along with a couple of other things). I think what you want is to have an #context that simply defines terms you want to use in the body of the JSON, where you can define your nodes and they're relationships.
This might be something like the following:
{
"#context": {
"edm" : "http://www.europeana.eu/schemas/edm/",
"ore": "http://example/",
"edm:aggregatedCHO": {"#type": "#id"}
},
"#id": "ore:Aggregation",
"edm:aggregatedCHO": "edm:ProvidedCHO"
}
It's always good to test your JSON-LD on the JSON-LD playground, or some similar service or tool.

Related

How to enforce an array on "#type" in jsonld?

Given a context with an aliased type like this:
{
"#context" : {
"type" : "#type"
}
}
How can an array be enforced onto the data like with using
"#container" : "#set"
?
In JSON-LD 1.0 this can't be achieved, as #type has its definition fixed by the specification. You can create aliases (such as type) but you can't change the behavior.
In the forthcoming JSON-LD 1.1, this has issue has been solved, and you can do exactly as proposed -- add #container: #set to the definition, and the compaction algorithm will add the types to an array.
The relevant issue in the 1.1 working group: https://github.com/w3c/json-ld-syntax/issues/34

spring data mongo Language annotation

i'm trying to figure out how to use the #Language annotation from spring-data-rest-mongo project;
I would like to store and retrive mongo document and do query on them; the simple document is as follow:
{
id: "abc",
name: "light",
"description": "wave or particle"
}
I would like to store it and retrive it with different languages;
any hint about it?
some sample using spring-data-rest would be greatly appreciated
thanks a lot
The #Language annotation is used to set the language_override property for a full text index and therefore does not help designing a collection of mulitlingual documents.
For more information please see the MongoDB Text Indexes and the Spring Data MongoDB Full Text Search support.
To perform a search for a certain language I usually follow this approach: Multi-language documents example
The entity
#Document
#CompoundIndex(def = "{'language': 1, 'textProperty': 'text'}")
The repository
#Query("{'language': ?0, $text: {$search: ?1, $language: ?0}}")
Stream<TheDocuemnt> findTheDocument(String language, String criteria, Sort sort);

Can compacting arrays be more selective in JSON-LD framing?

In the question JSON-LD framing single object arrays was asked on how to make arrays from single objects while framing JSON-LD for all arrays (by adding an compactArrays option).
Is there any way to do it selectively? Starting from always having "#graph", and after that for some "major" nodes. Maybe some parameter can be given in the frame to indicate exception of the general option?
In my case arrays are actually sets.
Yep, you can do it per-property by setting the #collection attribute of the property to #set:
{
"#context": {
"arrayProperty": {
"#id": "http://example.com/something",
"#container": "#set"
}
},
...
"arrayProperty": []
}

Object-oriented models and backbone.js

Suppose I'm working with an API which returns JSON data, but which has a complex or variable structure. For example, a string-valued property may be a plain literal, or may be tagged with a language:
/* first pattern */
{ "id": 1,
"label": "a foo"
}
/* second pattern */
{ "id": 2,
"label": [ {"value": "a foo", "lang": "en"},
{"value": "un foo", "lang": "fr"}]
}
In my client-side code, I don't want to have view code worrying about whether a label is available in multiple-languages, and which one to pick, etc. Or I might want to hide the detailed JSON structure for other reasons. So, I might wrap the JSON value in an object with a suitable API:
/** Value object for foo instances sent from server */
var Foo = function( json ) {
this.json = json;
};
/** Return a suitable label for this foo object */
Foo.prototype.label = function() {
var i18n = ... ;
if (i18n.prefLang && _.isArray(this.json.label)) // ... etc etc
};
So this is all pretty normal value-object pattern, and it's helpful because it's more decoupled from the specific JSON structure, more testable, etc. OK good.
What I currently don't see a way around is how to use one of these value objects with Backbone and Marionette. Specifically, I'd like to use a Foo object as the basis for a Backbone Model, and bind it to a Marionette ItemView. However, as far as I can see, the values in a Model are taken directly from the JSON structure - I can't see a way to recognise that the objects are functions:
var modelFoo = new Backbone.Model( foo );
> undefined
modelFoo.get( "label" ).constructor
> function Function() { [native code] }
So my question is: what is a good way to decouple the attributes of a Backbone Model from the specifics of a given JSON structure, such as a complex API value? Can value objects, models and views be made to play nice?
Edit
Let me add one more example, as I think the example above focussing on i18n issues only conveys part of my concern. Simplifying somewhat, in my domain, I have waterbodies comprising rivers, lakes and inter-tidal zones. A waterbody has associated with it one or more sampling points, and each sampling point has a latest sample. This might come back from the data API on the server as something like:
{"id": "GB12345678",
"centre": {"lat": 1.2345, "long": "-2.3456"},
"type": "river",
"samplingPoints": [{"id": "sp98765",
"latestSample": {"date": "20130807",
"classification": "normal"}
}]
}
So in my view code, I could write expressions such as:
<%= waterbody.samplingPoints[0].latestSample.classification %>
or
<% if (waterbody.type === "river") { %>
but that would be horrible, and easily broken if the API format changes. Slightly better, I could abstract such manipulations out into template helper functions, but they are still hard to write tests for. What I'd like to do is have a value object class Waterbody, so that my view code can have something like:
<%= waterbody.latestClassification() %>
One of the main problems I'm finding with Marionette is the insistence on calling toJSON() on the models passed to views, but perhaps some of the computed property suggestions have a way of getting around that.
The cleanest solution IMO is to put the label accessor into the model instead of the VO:
var FooModel = Backbone.Model.extend({
getLabel : function(){
return this.getLocalized("label");
},
getLocalized : function(key){
//return correct value from "label" array
}
});
and let the views use FooModel#getLabel instead of FooModel#get("label")
--EDIT 1
This lib seems interesting for your use case as well: Backbone.Schema
It allows you to formally declare the type of your model's attributes, but also provides some syntax sugar for localized strings and allows you to create dynamic attributes (called 'computed properties'), composed from the values of other attributes.
--EDIT 2 (in response to the edited question)
IMO the VO returned from the server should be wrapped inside a model and this model is passed to the view. The model implements latestClassification, not the VO, this allows the view to directly call that method on the model.
A simple approach to this (possibly to simple for your implementation) would be to override the model's parse method to return suitable attributes:
var modelFoo = Backbone.Model.extend({
parse: function ( json ) {
var i18n = ... ;
if (i18n.prefLang && _.isArray(json.label)) {
// json.label = "complex structure"
}
return json;
}
});
That way only your model worries about how the data from the server is formatted without adding another layer of abstraction.

Using CouchDB-lucene how can I index an array of objects (not values)

Hello everyone and thanks in advance for any ideas, suggestions or answers.
First, the environment: I am using CouchDB (currently developing on 1.0.2) and couchdb-lucene 0.7. Obviously, I am using couchdb-lucene ("c-l" hereafter) to provide full-text searching within couchdb.
Second, let me provide everyone with an example couchdb document:
{
"_id": "5580c781345e4c65b0e75a220232acf5",
"_rev": "2-bf2921c3173163a18dc1797d9a0c8364",
"$type": "resource",
"$versionids": [
"5580c781345e4c65b0e75a220232acf5-0",
"5580c781345e4c65b0e75a220232acf5-1"
],
"$usagerights": [
{
"group-administrators": 31
},
{
"group-users": 3
}
],
"$currentversionid": "5580c781345e4c65b0e75a220232acf5-1",
"$tags": [
"Tag1",
"Tag2"
],
"$created": "/Date(1314973405895-0500)/",
"$creator": "administrator",
"$modified": "/Date(1314973405895-0500)/",
"$modifier": "administrator",
"$checkedoutat": "/Date(1314975155766-0500)/",
"$checkedoutto": "administrator",
"$lastcommit": "/Date(1314973405895-0500)/",
"$lastcommitter": "administrator",
"$title": "Test resource"
}
Third, let me explain what I want to do. I am trying to figure out how to index the '$usagerights' property. I am using the word index very loosely because I really do not care about being able to search it, I simply want to 'store' it so that it is returned with the search results. Anyway, the property is an array of json objects. Now, these json objects that compose the array will always have a single json property.
Based on my understanding of couchdb-lucene, I need to reduce this array to a comma separated string. I would expect something like "group-administrators:31,group-users:3" to be a final output.
Thus, my question is essentially: How can I reduce the $usagerights json array above to a comma separated string of key:value pairs within the couchdb design document as used by couchdb-lucene?
A previous question I posted regarding indexing of tagging in a similar situation, provided for reference: How-to index arrays (tags) in CouchDB using couchdb-lucene
Finally, if you need any additional details, please just post a comment and I will provide it.
Maybe I am missing something, but the only difference I see from your previous question, is that you should iterate on the objects. Then the code should be:
function(doc) {
var result = new Document(), usage, right;
for(var i in doc.$usagerights) {
usage = doc.$usagerights[i];
for(right in usage) {
result.add(right + ":" + usage[right]);
}
}
return result;
}
There's no requirement to convert to a comma-separated list of values (I'd be intrigued to know where you picked up that idea).
If you simply want the $usagerights item returned with your results, do this;
ret.add(JSON.stringify(doc.$usagerights),
{"index":"no", "store":"yes", "field":"usagerights"});
Lucene stores strings, not JSON, so you'll need to JSON.parse the string on query.

Resources