MongoDB i JSON-LD

 

MongoDB

 

Informacje wstępne

MongoDB jest bazą danych typu NoSQL do przechowywania dokumentów (JSON - JavaScript Object Notation). Dane przechowywane w zagnieżdżonej formie i mogą być odpytywane w sposób ad hoc. MongoDB narzuca brak schematu danych. Dokumenty mogą opcjonalnie zawierać pola lub typy, których nie zawierają inne dokumenty w kolekcji. Mongo jest dobrym wyborem w przypadku aplikacji webowych, gdzie mamy do czynienia z dużą skalą danych o elastycznym schemacie. Brak schematu pozwala bazie Mongo na rozrastanie się i zmienianie wraz z modelem danych. Mongo posiada mechanizmy wspierające rozpraszanie danych (map-reduce).

 

Uruchomienie

Linię komend MongoDB można uruchomić z konsoli (Linux) poleceniem mongo.

 

Linia komend

Aby wybrać istniejącą bazę albo stworzyć nową, użyj funkcji use z linii komend.

Przykładową bazę dotyczącą muzyki o nazwie music można stworzyć w następujący sposób (UWAGA: korzystając ze zdalnego webowego interfejsu, polecenie use nie jest dostępne, a każda sesja przeglądarki dostaje własną bazę danych).

 

> use music

switched to db music

 

Następnie stworzymy nową kolekcję. Ponieważ nie jest wymagany schemat, stworzenie kolekcji jest tak proste jak wstawienie pierwszego rekordu. Poniższy kod wstawia/tworzy kolekcję albums:

 

> db.albums.insert({

artist: "U2",

title: "The Joshua Tree",

released: ISODate("1987-09-03"),

genre: ["rock", "folk rock", "alternative rock"],

recorded : {

period: "from January 1986 to January 1987",

country: "Ireland"

}

})

 

Aby wyświetlić listę dostępnych kolekcji dla aktualnej bazy danych używamy polecenia:

 

> show collections

albums

system.indexes

 

Zawartość kolekcji może zostać wyświetlona za pomocą polecenia find().

 

> db.albums.find()

 

{ "_id" : ObjectId("548b647d8f746f116242bb62"), "artist: U2", "title" : "The Joshua Tree", "released" : ISODate("1987-09-03T00:00:00Z"), "genre" : [ "rock", "folk rock", "alternative rock" ], "recorded" : { "period" : "from January 1986 to January 1987", "country" : "Ireland" } }

 

Pole _id oznacza numeryczny klucz główny, który jest inkrementacyjnie (automatycznie) zwiększany.

 

JavaScript

Natywny język Mongo to JavaScript. Komendy funkcjami JavaScript, a baza i kolekcja obiektami JavaScript.

 

> typeof db

object

> typeof db.albums

object

> typeof db.albums.insert

function

 

Chcąc podejrzeć kod funkcji należy wywołać bez parametrów (lub nawiasów). Stwórzmy swoją własną funkcję do wstawiania albumów do bazy, wprowadzając kod po prostu z linii komend:

 

 > function insertAlbum(

   artist, title, released, genre,

   recorded_info

   ){

    db.albums.insert({

    artist:artist,   

    title:title,

    released:ISODate(released),

    genre:genre,

    recorded:recorded_info

    });

  }

 

Następnie możemy wywołać funkcję:

 

> insertAlbum("Michael Jackson", "Thriller", '1982-11-30', ["pop","R&B","funk","rock"], {country:"USA"})

> insertAlbum("Metallica","Metallica", '1991-08-12',["heavy metal"],{period:"Oct 1990-June 1991"})

> insertAlbum("Norah Jones","Come Away with Me",'2001-02-26',["jazz"],{period:"2001",country:"USA"})

> insertAlbum("Siekiera","Nowa Aleksandria",'1988-07-27',["punk rock", "coldwave"],{country:"Poland"})

> insertAlbum("Dżem","Cegła",'1985-10-01',["blues rock"],{country:"Poland"})

 

 

Następnie, możesz użyć funkcji db.albums.find() aby wyświetlić wprowadzone dane.

W Mongo możliwe jest wydawanie różnych zapytań, poprzez wyspecyfikowanie nazw pól, zakresów wartości, bądź też kombinacji kryteriów, np.:

 

>db.albums.find({"genre":"rock"})

 

Dozwolone jest użycie operatorów, takich jak np. operatorów zakresu czy też operatorów wykorzystujących wyrażenia regularne. Składnia operatorów warunkowych spełnia schemat: { $op : value }, gdzie

 

$op to operacja jak np. $lte (less or equal to).

>db.albums.find({released: {$lte: ISODate('1991-08-12')}, "genre":"rock"})

 

Jeśli chcemy aby któreś pole nie było zwracane w wynikach to ustawiamy jego wartość na 0.

 

Zagnieżdżone dane

 

Mongo jest zaprojektowane z myślą o zagnieżdżonych danych, które można odpytywać na różne sposoby:

* poprzez podanie dokładnie pasujących wartości:

 

db.albums.find(

{ genre : 'rock' },

{ _id : 0, title : 1, genre : 1 }

)

 

* poprzez podanie częściowo pasujących wartości:

 

db.albums.find(

{ genre : /metal/ },

{ _id : 0, title : 1, genre : 1 }

)

 

* poprzez podanie wszystkich pasujących wartości:

 

db.albums.find(

{ genre : { $all : ['rock', 'funk']} },

{ _id : 0, title : 1, genre : 1 }

)

 

* lub brak pasujących wartości:

 

db.albums.find(

{ genre : { $nin : ['rock', 'jazz']} },

{ _id : 0, title : 1, genre : 1 }

)

 

Zaletą Mongo jest możliwość odpytywania zagnieżdżonych danych:

 

db.albums.find(

{ 'recorded.country' : 'Ireland' },

{ _id : 0, title : 1, recorded : 1 }

)

 

db.albums.find(

{ 'recorded.country' : { $exists : false } },

{ _id : 0, title : 1, recorded : 1 }

)

 

 

Update

Chcielibyśmy teraz zmienić album „Cegłai opisać go dodatkowym typem (genre) muzyki. Do tego celu mamy do dyspozycji funkcję update, która ma dwa parametry: pierwszy jest kryterium zapytania - obiekt w tym samym stylu jak podawany na wejście funkcji find(). Drugi parametr jest albo obiektem, którego pola zastąpią pasujący dokument albo operacją modyfikacji. W naszym przypadku, chcemy użyć modyfikatora, który za pomocą $set ustawi wartość pola genre na [„blues rock”, „rock”]:

 

>db.albums.update(

{ "title" : "Cegła" }, { $set : { "genre" : ["blues rock", "rock"] } }

)  

 

Chcąc dodać nowe pole z wartością, można to zrobić w podobny sposób:

 

>db.albums.update(

{ "title" : "Cegła" }, { $set : { "label" : "Polskie Nagrania Muza" } }

)  

 

JSON-LD

JSON-LD jest standardem W3C od stycznia 2014. JSON-LD jest formatem serializacji Linked Data do JSON.

 

Zacznijmy od przykładowego dokumentu JSON:

 

{

  "name": "Peter Gabriel",

  "homepage": "http://www.petergabriel.com",

  "image": "http://upload.wikimedia.org/wikipedia/commons/2/2b/Peter_Gabriel_Allan_Warren.jpg"

}

 

Żeby reprezentować taki dokument w sieci WWW jako „Linked Data”, dodamy unikalne identyfikatory (IRI). W tym celu wykorzystamy słownictwo schema.org.

 

{

  "http://schema.org/name": "Peter Gabriel",

  "http://schema.org/url": { "@id": "http://www.petergabriel.com" }, 

  "http://schema.org/image": { "@id": "http://upload.wikimedia.org/wikipedia/commons/2/2b/Peter_Gabriel_Allan_Warren.jpg" }

}

 

'@id' jest słowem kluczowym, które oznacza, że dana wartość jest identyfikatorem typu IRI.

Chociaż dodaliśmy unikalne identyfikatory do własności i wartości, to powyższy zapis jest dosyć rozwlekły. Żeby temu zaradzić w JSON-LD wprowadza się pojęcie kontekstu (context).

 

Kontekst

Kontekst pozwala użyć skróconych termów poprzez odwzorowanie termów do IRI. Przykładowo:

 

{

  "@context":

  {

    "name": "http://schema.org/name", 

    "image": {

      "@id": "http://schema.org/image", 

      "@type": "@id" 

    },

    "homepage": {

      "@id": "http://schema.org/url", 

      "@type": "@id"  

    }

  }

}

 

Powyższy przykład definiuje 'name' jako skrót 'http://schema.org/name', 'image' jako skrót 'http://schema.org/image' i 'homepage' jako skrót 'http://schema.org/url'. W powyższym przykładzie, ”@type”: ”@id” oznacza, że wartość łańcuchowa związana z 'image' lub 'homepage' powinna być interpretowana jako identyfikator typu IRI. Powyższy kontekst pokazuje, że wartość definicji termu może być albo: prostym łańcuchem, odwzorowaniem termu w IRI lub obiektem JSON.

Wstawmy podany wyżej kontekst do nowej kolekcji persons w naszej bazie MongoDB.

 

>db.persons.insert (

{

  "@context":

  {

    "name": "http://schema.org/name", 

    "image": {

      "@id": "http://schema.org/image", 

      "@type": "@id" 

    },

    "homepage": {

      "@id": "http://schema.org/url", 

      "@type": "@id"  

    }

  }

}

)

 

Konteksty mogą być osadzone w dokumentach lub można się do nich odwołać przez referencję. Zakładając, że dokument kontekstu może być pobrany z http://json-ld.org/contexts/person.jsonld, można zapisać do niego referencję w jednej linii. Dzięki temu dokument JSON-LD może być wyrażony bardziej zwięźle:

 

{

  "@context": "http://json-ld.org/contexts/person.jsonld",

  "name": "Peter Gabriel",

  "homepage": "http://www.petergabriel.com",

  "image": "http://upload.wikimedia.org/wikipedia/commons/2/2b/Peter_Gabriel_Allan_Warren.jpg"

}

 

Dodajmy powyższy dokument do naszej bazy MongoDB (do kolekcji 'persons'):

 

>db.persons.insert(

{

  "@context": "http://json-ld.org/contexts/person.jsonld",

  "name": "Peter Gabriel",

  "homepage": "http://www.petergabriel.com",

  "image": "http://upload.wikimedia.org/wikipedia/commons/2/2b/Peter_Gabriel_Allan_Warren.jpg"

}

)

 

Kontekst, do którego odnosi się referencja, nie tylko specyfikuje terminy odwzorowane w IRI w słownictwie schema.org, ale także specyfikuje, że wartości łańcuchowe powiązane z własnościami 'homepage' i 'image' mogą być interpretowane jako IRI (”@type”: ”@id”). Taka informacja pozwala developerom na wzajemne ponowne wykorzystanie danych bez konieczności uzgadniania w jaki sposób ich dane będą interoperacyjne strona po stronie.

 

IRI

Ponieważ JSON-LD serializuje model 'Powiązanych Danych', większość węzłów i własności jest identyfikowanych poprzez IRI.

 

Identyfikator węzła

 

W JSON-LD, węzeł jest identyfikowany poprzez słowo kluczowe @id. Przykładowo:

{

  "@context":

  {

    ...

    "name": "http://schema.org/name"

  },

  "@id": "http://www.petergabriel.com",

  "name": "Peter Gabriel",

  ...

}

 

Specyfikacja typu

 

Typ poszczególnego węzła może być wyspecyfikowany poprzez użycie słowa kluczowego @type. W 'Powiązanych Danych' typy mają unikalne identyfikatory (IRI).

 

{

...

  "@id": "http://en.wikipedia.org/wiki/Peter_Gabriel",

  "@type": "http://schema.org/Person",

...

}

 

Dodajmy do naszej bazy typ zasobu:

 

>db.persons.update(

{ "name": "Peter Gabriel" }, { $set : { "@type" : "http://schema.org/Person" } }

)

 

Skrócone IRI

Skrócone IRI to sposób na wyrażenie IRI za pomocą np. prefiksu. Przykładowo:

 

{

  "@context":

  {

    "foaf": "http://xmlns.com/foaf/0.1/"

...

  },

  "@type": "foaf:Person"

  "foaf:name": "Peter Gabriel",

...

}

 

Osadzanie

Dzięki możliwości osadzania w JSON-LD można używać obiektów węzłów jako wartości własności. Jest to powszechnie wykorzystywany mechanizm do tworzenia relacji rodzic-dziecko pomiędzy dwoma węzłami. Przykładowo, dwa węzły powiązane poprzez własność z pierwszego węzła:

 

{

...

  "name": "Peter Gabriel",

  "knows":

  {

    "@type": "Person",

    "name": "Kate Bush",

  }

...

}

 

Zbiory i listy

Zbiór wartości może zostać przedstawiony w zwięzły sposób poprzez użycie tablic JSON. Przykładowo (uwaga: kolejność nie ma znaczenia w przypadku JSON-LD):

 

{

...

  "@id": "http://en.wikipedia.org/wiki/Bono",

  "nick": [ "Bono", "Bono Vox" ],

...

}

 

Wynikiem będzie wygenerowanie następujących danych (bez narzuconej kolejności):

Subject

Property

Value

http://en.wikipedia.org/wiki/Bono

http://xmlns.com/foaf/0.1/nick

Bono

http://en.wikipedia.org/wiki/Bono

http://xmlns.com/foaf/0.1/nick

Bono Vox

 

Wiele wartości może także być wyrażonych w rozszerzonej formie:

 

{

  "@id": "http://example.org/books/10",

  "dc:title":

  [

    {

      "@value": "Ostatnie życzenie",

      "@language": "pl"

    },

    {

      "@value": "The Last Wish",

      "@language": "en"

    }

  ]

}

 

W efekcie zostaną wygenerowane następujące dane:

Subject

Property

Value

http://example.org/books/10

http://purl.org/dc/terms/title

Ostatnie życzenie

http://example.org/books/10

http://purl.org/dc/terms/title

The Last Wish

 

Dodajmy do naszej bazy osoby, które zna Peter Gabriel:

 

>db.persons.update(

{ "name": "Peter Gabriel" },

{ $set :

{

"knows":

  [

  {

    "@type": "Person",

    "name": "Kate Bush"

  },

  {

    "@type": "Person",

    "name": "Phil Collins"

  },

  ]

 }

}

)

 

Osadzanie JSON-LD w dokumentach HTML

Znaczniki HTML script mogą być użyte do osadzenia bloków danych w dokumentach. W ten właśnie sposób, treść JSON-LD może być łatwo osadzona w HTMLu poprzez umieszczenie jej w elemencie script z atrybutem type ustawionym na application/ld+json.

Przykład:

 

<script type="application/ld+json">

{

  "@context": "http://json-ld.org/contexts/person.jsonld",

  "@id": "http://dbpedia.org/resource/Marie_Curie",

  "name": "Maria Skłodowska-Curie",

  "born": "1867-11-07",

  "spouse": "http://dbpedia.org/resource/Pierre_Curie"

}

</script>

 

Zadania

1  Sformułuj zapytanie o wszystkie albumy, które reprezentują gatunek (genre) „rock”.

2  Stwórz nową kolekcję o nazwiecds”. Wstaw do kolekcji produkt, który jest albumem (z metadanymi jak w ćwiczeniach w tutorialu) i który jest dodatkowo opisany atrybutami: cena, ilość magazynowa, recenzje (w liczbie 2).

3  Sformułuj zapytanie o ludzi (name), których zna Peter Gabriel.