The document discusses the integration of JSON-LD and MongoDB for enhanced client-side graph queries in single-page applications. It highlights JSON-LD as a format for linked data representation and MongoDB as a document store for efficient data management. An example is provided using the game 'Call of Duty: Black Ops' to illustrate the JSON-LD structure and its context in the application.
JSON-LD and
MongoDB
Powering Linked Web Apps
Gregg Kellogg
gregg@greggkellogg.net
@gkellogg
2.
JSON-LD and Mongo
•JSON-LD – graph expression in JSON
• MongoDB – easily query JSON documents
• Together – efficient graph query optimized
for client-side processing
3.
Use Case
• WebApps:Single Page Applications (SPAS)
• Use JSON as native object representation
• REST access to web service mirroring
objects
• MongoDB document store maintaining
equivalent object representations
• Data is linked, internally and externally (RDF)
4.
JSON-LD
@graph
@context
@id
JSON-based syntax to express linked data
@language
@value
@list
@vocab
@type @set
5.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld",
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame",
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ",
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
],
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"],
"name": "Call of Duty: Black Ops",
"publisher": [
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
6.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame",
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ",
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
],
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"],
"name": "Call of Duty: Black Ops",
"publisher": [
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
7.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ",
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
],
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"],
"name": "Call of Duty: Black Ops",
"publisher": [
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
8.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ", Type same as rdf:type
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
],
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"],
"name": "Call of Duty: Black Ops",
"publisher": [
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
9.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ", Type same as rdf:type
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
], Data-typed values
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"],
"name": "Call of Duty: Black Ops",
"publisher": [
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
10.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ", Type same as rdf:type
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
], Data-typed values
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"], Simple string values
"name": "Call of Duty: Black Ops",
"publisher": [
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
11.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ", Type same as rdf:type
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
], Data-typed values
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"], Simple string values
"name": "Call of Duty: Black Ops",
"publisher": [ (unordered) arrays of values
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
],
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
12.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ", Type same as rdf:type
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
], Data-typed values
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"], Simple string values
"name": "Call of Duty: Black Ops",
"publisher": [ (unordered) arrays of values
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
], subject reference links to other resources
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001",
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
13.
JSON, as expected
{
"@context": "/contexts/wikia.jsonld", Context defines terms
"@id": "500f1a1b6e7f1827ba000001",
"@type": "wikia:VideoGame", Identifier treated as IRI
"contentRating": [
"ESRB: Mature (DS version is Teen)",
"PEGI: 18+ (DS version is 16+) ", Type same as rdf:type
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"
], Data-typed values
"datePublished": "2011-11-09",
"description": "Primary game entry point",
"genre": ["First-person shooter"], Simple string values
"name": "Call of Duty: Black Ops",
"publisher": [ (unordered) arrays of values
{"@id": "501067246e7f184553000001"},
{"@id": "5010675a6e7f18464d000001"}
], subject reference links to other resources
"event": [
"500f28856e7f187196000001",
"500f44556e7f18f7ef000001", Arrays may be ordered in @context
"500f449e6e7f18f94b000001",
"500f44e26e7f18fa75000001"
],
"wikia:platform": ["Xbox 360","PS3","PC","Wii","DS"]
}
Syntactic Conventions
• Keysrepresent unique properties
• Values may be singular or multiple
• May use strings for most value
representations, with typing information
maintained in a context.
In-memory linking
Flattened Form Linked Form:
{
"@id": "500f1a1b6e7f1827ba000001", @id 500f1a1b6e7f1827ba000001
"type": "wikia:VideoGame",
"schema:name": "Call of Duty: Black Ops", type wikia:VideoGame
"wikia:event": [
{"@id": "500f28856e7f187196000001"}, name "Call of Duty: Black Ops"
{"@id": "500f44556e7f18f7ef000001"}, event 500f28856e7f187196000001
{"@id": "500f449e6e7f18f94b000001"},
{"@id": "500f44e26e7f18fa75000001"}
]
},
{ @id 500f28856e7f187196000001
"@id": "500f28856e7f187196000001",
type cod:Mission
"type": "cod:Mission",
"schema:name": "Operation 40", name "Operation 40"
"schema:startDate": "1961-04-17", startDate "1961-04-17"
"wikia:eventIn": [
{"@id": "500f1a1b6e7f1827ba000001"} event 500f1a1b6e7f1827ba000001
]
}
24.
Turtle Mapping
{ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
"@context": "/contexts/wikia.jsonld", @prefix schema: <http://schema.org/> .
"@id": "500f1a1b6e7f1827ba000001", @prefix wikia: <http://data.wikia.com/terms#> .
"@type": "wikia:VideoGame", @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
"contentRating": [
"ESRB: Mature (DS version is Teen)", <500f1a1b6e7f1827ba000001> a wikia:VideoGame;
"PEGI: 18+ (DS version is 16+) ", schema:contentRating "ESRB: Mature (DS version is Teen)"@en,
"USK: 18 CERO: Z OFLC: MA15+ (DS version is M)" "PEGI: 18+ (DS version is 16+) "@en,
], "USK: 18 CERO: Z OFLC: MA15+ (DS version is M)"@en;
"datePublished": "2011-11-09", schema:datePublished: "2011-11-09"^^xsd:dateTime;
"name": "Call of Duty: Black Ops", schema:name "Call of Duty: Black Ops"@en;
"publisher": [ schema:publisher <501067246e7f184553000001>,
{"@id": "501067246e7f184553000001"}, <5010675a6e7f18464d000001> .
{"@id": "5010675a6e7f18464d000001"} wikia:event <500f28856e7f187196000001>,
], ...;
"wikia:event": [ .
{"@id": "500f28856e7f187196000001"},
...
]
}
25.
More JSON-LD Features*
• @set, @list, • Embedded
Compact IRIs, @context
Unlabeled Nodes definitions
• Language maps • Named Graphs
• Property generators
* http://json-ld.org/spec/latest/json-ld-syntax
26.
History
• 2009 – Started as a way to project from the RDFa API
• Developers want solutions to work within HTML
applications
• Desire for JSON-idiomatic way of representing RDF
(Linked Data)
• Adapt existing JSON APIs to Linked Data
27.
History
• 2011 –W3C Community Group launched
• Broad Participation
• Separation of Syntax from API
• Proposed to W3C RDF 1.1 Working
Group
28.
History
• 2012 –RDF WG abandons other JSON
serialization efforts (RDF/JSON)
• JSON-LD accepted as official work item
• Community Group drafts final report
• RDF WG publishes JSON-LD (Syntax and
API) as FPWD
29.
MongoDB
• JSON-like documentstore
• BSON supports extra datatypes
• Certain key patterns are restricted
• e.g., “.” not allowed in a key
• Query on value = pattern or value includes
pattern
Wikia Application
• ExpressWiki content as structured data
• Wiki markup doesn’t naturally include
semantic cues (Semantic Media Wiki
aside).
• Add semantic markup to HTML generated
from Wikis in RDFa
• Aggregate structured content through
JSON-LD/MongoDB powered data service
32.
Service Architecture
• MongoDBpersistence
• JSON document representation
• JSON-LD describedby link header
• Ruby/Sinatra web service
• Content-negotiated access to data
• JSON-LD, HTML, Turtle, ...
33.
Document Model
{
• Use aliases for @id and "id": "500f1a1b6e7f1827ba000001",
"type": "wikia:VideoGame",
@type keywords "name": "Call of Duty: Black Ops",
"publisher": [
• Simplifies use within "501067246e7f184553000001",
"5010675a6e7f18464d000001"
client-side MVC ],
"wikia:event": [
frameworks (e.g. "500f28856e7f187196000001"
backbone.js) ]
}
34.
Document Model
{
"id": "500f1a1b6e7f1827ba000001",
"type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
• Individual subject "publisher": [
"501067246e7f184553000001",
definition as Mongo "5010675a6e7f18464d000001"
document ],
"wikia:event": [
"500f28856e7f187196000001"
]
}
35.
Document Model
{
"id": "500f1a1b6e7f1827ba000001",
• Use expanded subject "type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
references "publisher": [
{"id": "501067246e7f184553000001"},
{"id": "5010675a6e7f18464d000001"}
➡This allows simple ],
"wikia:event": [
traversal for graphify {"id": "500f28856e7f187196000001"}
]
}
36.
Document Model
{
"id": "500f1a1b6e7f1827ba000001",
•
"type": "wikia:VideoGame",
Gather subject "name": "Call of Duty: Black Ops",
"publisher": [
references under a {"id": "501067246e7f184553000001"},
hidden key {"id": "5010675a6e7f18464d000001"}
],
"wikia:event": [
➡This allows easy ],
{"id": "500f28856e7f187196000001"}
querying for objects "_references": [
referencing another "501067246e7f184553000001",
"5010675a6e7f18464d000001",
object "500f28856e7f187196000001"
]
}
37.
Document Model
GET http://example.com/collection/
500f1a1b6e7f1827ba000001
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
Link: </contexts/wikia.jsonld>; rel="describedby";
type="application/ld+json"
• Return context as HTTP {
Link Header "id": "500f1a1b6e7f1827ba000001",
"type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
"publisher": [
{"id": "501067246e7f184553000001"},
{"id": "5010675a6e7f18464d000001"}
],
"wikia:event": [
{"id": "500f28856e7f187196000001"}
]
}
38.
Restful Endpoints
GET http://example.com/collection/?
withType="schema:Corporation"
Accept: application/json
HTTP/1.1 200 OK
• index – query collection Content-Type: application/json;charset=utf-8
Link: </contexts/wikia.jsonld>; rel="describedby";
type="application/ld+json"
• by type – return [
objects having (or {
containing) a type "id": "501067246e7f184553000001",
"type": "schema:Corporation",
"name": "Activision",
"url": "http://callofduty.wikia.com/wiki/Activision"
}, {
"id": "5010675a6e7f18464d000001",
"type": "schema:Corporation",
"name": "Square Enix (Japan)"
}
]
39.
Restful Endpoints
•
GET http://example.com/collection/?
index – query collection referencing="500f1a1b6e7f1827ba000001"
Accept: application/json
• by referencing – HTTP/1.1 200 OK
return objects Content-Type: application/json;charset=utf-8
Link: </contexts/wikia.jsonld>; rel="describedby";
referencing another type="application/ld+json"
object [{
"id": "500f28856e7f187196000001",
• Build out space "cod:game": {"id": "500f1a1b6e7f1827ba000001"},
"schema:name": "Operation 40",
around an object "schema:startDate": "1961-04-17T00:00:00",
"wikia:eventIn": [{"id": "500f1a1b6e7f1827ba000001"}],
"wikia:next": {"id": "500f44556e7f18f7ef000001"},
• Similar to SPARQL "wikia:objective": [
{"id": "501445266e7f1847c6000001"},
describe {"id": "50143e1e6e7f18256d000001"},
...
],
}, ...]
40.
Restful Endpoints
GET http://example.com/collection/
500f1a1b6e7f1827ba000001
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
Link: </contexts/wikia.jsonld>; rel="describedby";
•
type="application/ld+json"
GET – return single
{
object "id": "500f1a1b6e7f1827ba000001",
"type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
"publisher": [
{"id": "501067246e7f184553000001"},
{"id": "5010675a6e7f18464d000001"}
]
}
41.
Restful Endpoints
POST http://example.com/collection/
Accept: application/json
Content-Type: application/json
{
• POST – Create new "type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops"
object }
HTTP/1.1 201 Created
•
Content-Type: application/json;charset=utf-8
Good practice to Link: </contexts/wikia.jsonld>; rel="describedby";
type="application/ld+json"
maintain dateCreated Location: http://example.com/collection/
and dateModified 500f1a1b6e7f1827ba000001
equivalents {
"id": "500f1a1b6e7f1827ba000001",
"type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
"dateCreated": "2012-08-23T14:00:00-08:00",
"dateModified": "2012-08-23T14:00:00-08:00",
}
42.
Restful Endpoints
PUT http://example.com/collection/
500f1a1b6e7f1827ba000001
Accept: application/json
Content-Type: application/json
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
• PUT – Update object Link: </contexts/wikia.jsonld>; rel="describedby";
type="application/ld+json"
• Good practice to {
"id": "500f1a1b6e7f1827ba000001",
update dateModified "type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
equivalent "publisher": [
{"id": "501067246e7f184553000001"},
{"id": "5010675a6e7f18464d000001"}
],
"dateCreated": "2012-08-23T14:00:00-08:00",
"dateModified": "2012-08-23T14:15:00-08:00",
}
Restful Endpoints
GET http://example.com/collection/
500f1a1b6e7f1827ba000001/publisher/
Accept: application/json
HTTP/1.1 200 OK
• path – relational query Content-Type: application/json;charset=utf-8
Link: </contexts/wikia.jsonld>; rel="describedby";
type="application/ld+json"
• Return objects having [
a property {
"id": "501067246e7f184553000001",
relationship with "type": "schema:Corporation",
another object "name": "Activision",
"url": "http://callofduty.wikia.com/wiki/
Activision"
}, {
"id": "5010675a6e7f18464d000001",
"type": "schema:Corporation",
"name": "Square Enix (Japan)"
}
]
45.
Restful Endpoints
GET http://example.com/collection/
500f1a1b6e7f1827ba000001
Accept: application/ld+json
HTTP/1.1 200 OK
Content-Type: application/ld+json;charset=utf-8
• GET – as explicit JSON- {
"@context": "/contexts/wikia.jsonld",
LD "id": "500f1a1b6e7f1827ba000001",
"type": "wikia:VideoGame",
"name": "Call of Duty: Black Ops",
"publisher": [
{"id": "501067246e7f184553000001"},
{"id": "5010675a6e7f18464d000001"}
]
}
46.
Working with data
• Application Structure
• Ruby/Sinatra REST
service
• JavaScript/Backbone.js
client
{
• Alias JSON-LD "@context": {
"id": "@id",
keywords for
"type": "@type"
convenience
}
}
47.
MVC Client
• Natural access from client-side MVC (e.g.,
backbone.js)
Collection
// Object collection, handles objects constructed from OWL classes and properties.
// Initial fetch is only for VideoGame types, as referenced objects are
// fetched, they are added to the collection.
Wikia.ObjectCollection = Backbone.Collection.extend({
initialize: function() { this.model = Wikia.ObjectModel; },
url: function() { return "/api/#{@vers}/#{@name}"; },
comparator: function(model) { return model.get('schema:name') }
...
}
48.
MVC Client
• Natural access from client-side MVC (e.g.,
backbone.js)
Model
// OWL model class and sub-classes for dealing with owl:Class,
// owl:DatatypeProperty, owl:ObjectProperty and owl:Datatype
Wikia.ObjectModel Backbone.Model.extend({
referencedObjects: function() { return this.resolve(_.flatten(_.toArray(this.attributes))); },
getModel: function(key, options) { return this._resolve this.get(key)) },
setModel: function(key, value) {...},
_resolve: function(value) {...},
...
}
49.
Summary
• JSON-LD is a light-weight layer for representing
linked data in JSON
• The MongoDB document model is a natural fit for
JSON-LD
• Not optimized for SPARQL; consider alternatives
• Single Page Applications benefit from linked data
principles
• RDF with OWL can be powerful when used
appropriately in the client
#5 JSON-LD brings a standard representation for expressing entity-value relationships using a few standard keywords and a consistent organizational structure for JSON Objects.\nObjects represent entities, with keys acting as properties.\n Properties always expand to full IRIs.\nArrays express a set of values associated with a property, unordered by default.\n Order expressed in @context or as an expanded value representation.\nValues are Object, string or native, with standard XSD representations for native types.\n Expanded form allows for more datatype and language variations.\n
#23 It&#x2019;s important to note that JSON-LD is a product of the W3C RDF Working group, and is as much &#x201C;RDF&#x201D; as any other serialization format.\nIn this case, we show a transformation from the JSON-LD format of a resource description to Turtle, an RDF format specifically intended to be humanly readable.\n
#57 What I've outlined is not really optimized for SPARQL. For performance, you're much better at storing triples as documents, then full-on subject definitions.\n\nThis application is more tuned for returning collections of subject definitions based on a fairly narrow query bounds (resources relevant to a particular point in game play) then general querying. In fact, I've considered that an evolution of the application I'm working on may well go to a generic SPARQL store, with good JSON-LD support, such as Stardog.\n\n