nosql-tutorial 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ #### {% title "CouchDB — Futon" %}
2
+
3
+ # CouchDB — Futon
4
+
5
+ Graficzny interfejs do CouchDB jest dostępny z URI:
6
+
7
+ http://127.0.0.1:5984/_utils/
8
+
9
+ albo:
10
+
11
+ http://localhost:5984/_utils/
12
+
13
+ Korzystamy z nakładki Futon aby utworzyć i usunąć bazę danych,
14
+ dodajemy i usuwamy dokument z bazy danych, dodajemy i usuwamy
15
+ załącznik. Tworzymy tymczasowy widok.
16
+
17
+
18
+ ## Tworzymy bazę i dodajemy do niej dokumenty
19
+
20
+ Tworzymy prostą bazę danych *sprawdziany*:
21
+
22
+ curl -X PUT http://127.0.0.1:5984/sprawdziany
23
+
24
+ w której będziemy zapisywać takie dokumenty:
25
+
26
+ nazwa: "jakie?"
27
+ wyniki: { "login1":wynik1, ...}
28
+
29
+ Dodajemy kilka dokumentów do bazy danych.
30
+ Tak to można zrobić z wiersza poleceń:
31
+
32
+ curl -X POST -d @sprawdziany.json http://127.0.0.1:5984/sprawdziany/_bulk_docs
33
+
34
+ gdzie w pliku *sprawdziany.json* wpisaliśmy:
35
+
36
+ :::json
37
+ {
38
+ "docs": [
39
+ {"_id":"1", "nazwa":"html", "wyniki":{"jacek":10, "agatka":20}},
40
+ {"_id":"2", "nazwa":"css", "wyniki":{"jacek":1, "agatka":12}},
41
+ {"_id":"3", "nazwa":"js", "wyniki":{"jacek":1, "agatka":12}}
42
+ ]
43
+ }
44
+
45
+ Możemy też dodać kilka dokumentów, korzystając z *Futona*. **Jak?**
46
+
47
+
48
+ ## Tymczasowe widoki
49
+
50
+ Tutaj:
51
+
52
+ http://127.0.0.1:5984/_utils/index.html
53
+
54
+ jest lista baz. A tutaj baza *sprawdziany*:
55
+
56
+ http://127.0.0.1:5984/_utils/database.html?sprawdziany
57
+
58
+ Tworzymy widok tymczasowy (lista rozwijana, prawy górny róg):
59
+ wybieramy **Temporary view**. Domyślny widok definiuje funkcja:
60
+
61
+ :::javascript
62
+ function(doc) {
63
+ emit(null, doc);
64
+ }
65
+
66
+ Uruchamiamy wpisaną *Map Function*.
67
+ Czy można odgadnąć czym jest argument *doc* tej funkcji?
68
+
69
+ W okienku *View Code* wpisujemy naszą pierwszą *Map Function*:
70
+
71
+ :::javascript
72
+ function(doc) {
73
+ var login, wynik, value;
74
+ if (doc.nazwa && doc.wyniki) {
75
+ for (login in doc.wyniki) {
76
+ wynik = doc.wyniki[login];
77
+ value = [login, doc.nazwa, wynik];
78
+ emit(wynik, value);
79
+ }
80
+ }
81
+ }
82
+
83
+ Sortowanie po wynikach. Jak posortować po *loginach*? (proste)
84
+
85
+ Druga funkcja map:
86
+
87
+ :::javascript
88
+ function(doc) {
89
+ var wynik, key;
90
+ if (doc.nazwa && doc.wyniki) {
91
+ for (var login in doc.wyniki) {
92
+ wynik = doc.wyniki[login];
93
+ key = [doc.nazwa, wynik];
94
+ emit(key, login);
95
+ }
96
+ }
97
+ }
98
+
99
+ Teraz sortowanie jest po `[doc.nazwa, wynik]`. Co to oznacza?
100
+
101
+
102
+ ## Konfiguracja
103
+
104
+ Jeśli w konfiguracji **httpd > bind address** zmienimy 127.0.0.1
105
+ na 0.0.0.0, to uzyskamy zdalny dostęp do Futona
106
+ i CouchDB. (Ale stracimy dostęp lokalny.)
107
+
108
+
109
+ ## Replikacja bazy danych
110
+
111
+ Do czego może się przydać?
112
+
113
+
114
+ ## Compacting database
115
+
116
+ Ważne! Dlaczego?
@@ -0,0 +1,53 @@
1
+ #### {% title "CouchDB – Ruby" %}
2
+
3
+ # CouchDB – Ruby
4
+
5
+ ## Korzystamy z gemu *rest-client*
6
+
7
+ Przykład z Wiki: [collation](http://wiki.apache.org/couchdb/View_collation):
8
+
9
+ :::ruby
10
+ # file: collseq.rb
11
+ require 'rubygems'
12
+ require 'restclient'
13
+ require 'json'
14
+
15
+ DB="http://127.0.0.1:5984/collator"
16
+ RestClient.delete DB rescue nil
17
+ RestClient.put "#{DB}",""
18
+ (32..126).each do |c|
19
+ RestClient.put "#{DB}/#{c.to_s(16)}", {"x"=>c.chr}.to_json
20
+ end
21
+ RestClient.put "#{DB}/_design/test", <<EOS
22
+ {
23
+ "views":{
24
+ "one":{
25
+ "map":"function (doc) { emit(doc.x,null); }"
26
+ }
27
+ }
28
+ }
29
+ EOS
30
+ puts RestClient.get("#{DB}/_design/test/_view/one")
31
+
32
+ ## Couchrest & irb
33
+
34
+ :::ruby
35
+ db = CouchRest.database!("http://localhost:5984/my_db")
36
+ attr = { "imie" => "Włodek", "login" => "wbzyl", "wiek" => "18" }
37
+ result = db.save_doc(attr)
38
+
39
+ Dalej
40
+
41
+ :::ruby
42
+ result['id']
43
+ record = db.get(result['id'])
44
+ record['_rev']
45
+ record['login'] = 'matwb'
46
+ result = db.save_doc(record)
47
+ record = db.get(result['id'])
48
+ db.delete_doc(record)
49
+
50
+
51
+ Zob. [Contacts](http://gist.github.com/112109),
52
+ [blog J. P. Wood’a](http://johnpwood.net/tag/couchrest/),
53
+ [Rails Wiki: CouchDB](http://wiki.rubyonrails.org/database-support/couchdb).
@@ -0,0 +1,162 @@
1
+ #### {% title "CouchDB — Widoki" %}
2
+
3
+ # CouchDB — Widoki
4
+
5
+ Zapytania SQL, takie jak to:
6
+
7
+ SELECT name, email, fax FROM contacts
8
+
9
+ nie mają sensu dla dokumentowych baz danych.
10
+
11
+ Dlaczego? Rozważyć wartości NULL. Rekordy w tabelach SQL a dokumenty w
12
+ dokumentowych bazach danych.
13
+
14
+ W dokumentowych bazach danych zamiast pisać zapytania
15
+ piszemy widoki. Cytat:
16
+ „Views are the primary tool used for querying and reporting on CouchDB
17
+ documents. There are two different kinds of views: permanent and
18
+ temporary views.”
19
+
20
+ Widoki są zapisywane w bazie jako specjalne **design documents**.
21
+ Widoki są powielane z zwykłymi dokumentami.
22
+
23
+
24
+ ## Widoki w CouchDB API
25
+
26
+ Tymczasowy widok, np. taki:
27
+
28
+ :::javascript
29
+ function(doc) {
30
+ emit(doc._id, doc);
31
+ }
32
+
33
+ wywołujemy z wiersza poleceń w taki sposób:
34
+
35
+ curl -X POST http://127.0.0.1:5984/sprawdziany/_temp_view \
36
+ -d '{"map":"function(doc) { emit(doc._id, doc); }"}'
37
+
38
+ Widok permanentny wstawiamy do bazy
39
+ z *id* **_design/*nazwa_widoku*** w taki sposób:
40
+
41
+ curl -X PUT http://127.0.0.1:5984/sprawdziany/_design/wyniki -d @ja.json
42
+
43
+ gdzie plik *ja.json* ma następującą zawartość:
44
+
45
+ :::json
46
+ {
47
+ "language": "javascript",
48
+ "views": {
49
+ "wyniki_jacka": {
50
+ "map": "function(doc) {
51
+ if (doc.nazwa && doc.wyniki['jacek']) {
52
+ emit(doc.nazwa, doc.wyniki['jacek']);
53
+ }
54
+ }"
55
+ },
56
+ "wyniki_agatki": {
57
+ "map": "function(doc) {
58
+ if (doc.nazwa && doc.wyniki['agatka']) {
59
+ emit(doc.nazwa, doc.wyniki['agatka']);
60
+ }
61
+ }"
62
+ }
63
+ }
64
+ }
65
+
66
+ Widoki permanentne wywołujemy inaczej (GET zamiast POST):
67
+
68
+ curl -X GET http://127.0.0.1:5984/sprawdziany/_design/wyniki/_view/wyniki_jacka
69
+ curl -X GET http://127.0.0.1:5984/sprawdziany/_design/wyniki/_view/wyniki_agatki
70
+
71
+ Ale łatwiejszy w dalszej obróbce byłby taki widok:
72
+
73
+ :::javascript
74
+ function(doc) {
75
+ if (doc.nazwa && doc.wyniki['jacek']) {
76
+ emit(doc._id, {"sprawdzian":doc.nazwa, "punkty":doc.wyniki['jacek']});
77
+ }
78
+ }
79
+
80
+ ## „Złączenia” w bazach CouchDB
81
+
82
+ Example: how you'd go about modeling a simple blogging system with “post” and
83
+ “comment” entities, where any blog post might have many comments.
84
+
85
+ Przykład z artykułu:
86
+ Christopher Lenz, [CouchDB "Joins"](http://www.cmlenz.net/archives/2007/10/couchdb-joins).
87
+
88
+ ### Komentarze inline
89
+
90
+ Utworzymy bazę zawierającą kilka takich dokumentów:
91
+
92
+ :::json
93
+ {
94
+ "author": "jacek",
95
+ "title": "Rails 2",
96
+ "content": "Bla bla…",
97
+ "comments": [
98
+ {"author": "agatka", "content": "…"},
99
+ {"author": "bolek", "content": "…"}
100
+ ]
101
+ }
102
+
103
+ Dane do umieścimy w bazie za pomocą skryptu
104
+ {%= link_to 'blog-inline.rb', '/doc/couchdb/blog-inline.rb' %}.
105
+
106
+ Widok:
107
+
108
+ :::javascript
109
+ function(doc) {
110
+ for (var i in doc.comments) {
111
+ emit(doc.comments[i].author, doc.comments[i].content);
112
+ }
113
+ }
114
+
115
+ Jakie problemy może dawać takie podejście?
116
+
117
+
118
+ ### Komentarze w osobnych dokumentach:
119
+
120
+ Utworzymy bazę zawierającą kilka postów:
121
+
122
+ :::json
123
+ {
124
+ "_id": "01"
125
+ "type": "post",
126
+ "author": "jacek",
127
+ "title": "Rails 3",
128
+ "content": "Bla bla bla …"
129
+ }
130
+
131
+ oraz komentarzy:
132
+
133
+ :::json
134
+ {
135
+ "type": "comment",
136
+ "post_id": "01",
137
+ "author": "agatka",
138
+ "content": "…"
139
+ }
140
+ {
141
+ "type": "comment",
142
+ "post_id": "01",
143
+ "author": "bolek",
144
+ "content": "…"
145
+ }
146
+
147
+ TODO:
148
+ Dane do umieścimy w bazie za pomocą skryptu
149
+ {%= link_to 'blog-separate.rb', '/doc/couchdb/blog-separate.rb' %}.
150
+
151
+ Poniższy widok, wypisuje komentarze zgrupowane po *post_id*:
152
+
153
+ :::javascript
154
+ function(doc) {
155
+ if (doc.type == "comment") {
156
+ emir(doc.post_id, {author: doc.author, content: doc.content});
157
+ }
158
+ }
159
+
160
+ Sprawdzić powyższe stwierdzenie.
161
+
162
+ Takie podejście ma swoje braki. Jakie?
@@ -0,0 +1,122 @@
1
+ #### {% title "CouchDB – Zaczynamy" %}
2
+
3
+ # CouchDB – Zaczynamy
4
+
5
+ Co to są [dokumentowe bazy danych] [document-oriented database]?
6
+
7
+ Dlaczego korzystamy z dokumentowych baz danych:
8
+
9
+ 1. Dokumentowe systemy baz danych są **schema-free**.
10
+ 1. Another advantage of document oriented databases is **the ease of
11
+ usage and programming** so that untrained business users, for example,
12
+ can create applications and design their own databases. Information
13
+ can be added without worrying about the "record size" and so
14
+ programmers simply need to build an interface to allow the
15
+ information to be entered easily.
16
+
17
+ Dwa cytaty ze strony [projektu CouchDB](http://couchdb.apache.org/):
18
+
19
+ „Apache CouchDB is a document-oriented database that can be queried and
20
+ indexed in a MapReduce fashion using JavaScript.”
21
+
22
+ „CouchDB provides a RESTful JSON API than can be accessed from any
23
+ environment that allows HTTP requests.”
24
+
25
+ Trochę historii:
26
+
27
+ * [Damien Katz](http://damienkatz.net/) – autor
28
+ * Przepisanie programu z C++ na Erlang – 2006
29
+ * Restful API – kwiecień 2006
30
+ * Pierwsza dostępna wersja 0.2 – sierpień 2006
31
+ * Przejście z XML na JSON, Javascript językiem zapytań – sierpień 2007
32
+ * [Map/Reduce][map-reduce] – luty 2008
33
+
34
+
35
+ ## Instalacja serwera CouchDB
36
+
37
+ Najłatwiej jest zainstalować serwer z pakietu:
38
+
39
+ * Fedora: `su –c 'yum install couchdb'`
40
+ * Ubuntu: ???
41
+
42
+ Sprawdzamy, czy instalacja przebiegła bez błędów:
43
+
44
+ curl http://127.0.0.1:5984/
45
+ => {"couchdb":"Welcome","version":"0.11.0b"}
46
+
47
+ Na koniec wchodzimy na stronę:
48
+
49
+ http://127.0.0.1:5984/_utils/
50
+
51
+ gdzie jest dostępny *Futon*, czyli narzędzie do administracji bazami
52
+ danych zarządzanymi przez CouchDB.
53
+
54
+ Klikając w odpowiednie zakładki *Futona* możemy wyświetlić
55
+ listę zainstalowanych baz danych, szczegóły konfiguracji itd.
56
+
57
+ Ale informacje te można też uzyskać inaczej, korzystając
58
+ z na przykład programu *curl*:
59
+
60
+ curl -X GET http://127.0.0.1:5984/_all_dbs
61
+ curl -X GET http://127.0.0.1:5984/_config
62
+
63
+ Na koniec kilka innych zapytań:
64
+
65
+ curl -X GET http://127.0.0.1:5984/_uuids?count=2
66
+ curl -X POST http://127.0.0.1:5984/_replicate?source=xxx&target=yyy
67
+
68
+ W odpowiedzi na każde żądanie HTTP (*request*), dostajemy
69
+ odpowiedź HTTP (*response*) w formacie [JSON][json].
70
+
71
+ **Co to jest:** HTTP request, HTTP response, format wymiany danych JSON?
72
+
73
+ Jeśli skorzystamy z opcji `-v` programu *curl*
74
+ to program wypisze szczegóły tego co robi, na przykład:
75
+
76
+ curl -vX POST http://127.0.0.1:5984/_replicate?source=xxx&target=yyy
77
+
78
+ (Chociaż tutaj *content-type* jest ustawiony na *text/plain;charset=utf-8*.
79
+ Dlaczego?)
80
+
81
+ [json]: http://www.json.org/ "JSON"
82
+
83
+
84
+ ## CRUD na bazach danych
85
+
86
+ CRUD to skrót od pierwszych liter słów:
87
+ Create, Read, Update, Delete.
88
+
89
+ Poniżej zobaczymy jak korzystając z programu *curl*
90
+ utworzyć nową bazę danych, usunąć bazę, pobrać informację o bazie
91
+ itd. Skorzystam ze ściągi:
92
+
93
+ * [Ściąga z API: Database level](http://wiki.apache.org/couchdb/API_Cheatsheet)
94
+
95
+ Tworzymy nową bazę o nazwie *xxx*:
96
+
97
+ curl -X PUT http://127.0.0.1:5984/xxx
98
+
99
+ Pobieramy info o bazie *xxx*:
100
+
101
+ curl -X GET http://127.0.0.1:5984/xxx
102
+
103
+ Usuwamy bazę *xxx*:
104
+
105
+ curl -X DELETE http://127.0.0.1:5984/xxx
106
+
107
+ Nie ma polecenia dla *Update*.
108
+ Omówić pozostałe operacje ze ściągi: *Database level*
109
+
110
+ **REST** to akronim od *Represenational State Transfer*.
111
+ Zwykle w kontekście WWW rozumiemy ten skrót tak:
112
+
113
+ * Dane są zasobami (ang. resources)
114
+ * Każdy zasób ma swój unikalny URI
115
+ * Na zasobach można wykonywać cztery podstawowe operacje CRUD
116
+ * Klient i serwer komunikują się ze sobą korzystając protokołu
117
+ bezstanowego. Oznacza to, że klient zwraca się z żądaniem do
118
+ serwera. Serwer odpowiada i cała konwersacja się kończy.
119
+
120
+
121
+ [document-oriented database]: http://en.wikipedia.org/wiki/Document-oriented_database "Document-oriented database"
122
+ [map-reduce]: http://en.wikipedia.org/wiki/MapReduce "MapReduce"