nosql-tutorial 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +25 -14
- data/Rakefile +2 -2
- data/VERSION.yml +2 -2
- data/lib/public/doc/activerecord/000-activerecord.rb +77 -0
- data/lib/public/doc/activerecord/100-datamapper.rb +60 -0
- data/lib/public/doc/activerecord/activerecord_spec_helper.rb +13 -0
- data/lib/public/doc/activerecord/datamapper_spec_helper.rb +15 -0
- data/lib/public/doc/couchdb/blog-inline.rb +60 -0
- data/lib/public/doc/couchdb/collseq.rb +22 -0
- data/lib/public/doc/datamapper/000-sqlite3.rb +65 -0
- data/lib/public/doc/datamapper/001-ale-kino.rb +69 -0
- data/lib/public/doc/datamapper/010-postgres.rb +95 -0
- data/lib/public/doc/datamapper/bug.rb +25 -0
- data/lib/public/doc/mail/mail-20.rb +40 -0
- data/lib/public/doc/mail/mail-21.rb +62 -0
- data/lib/public/doc/mail/mail-gmail.rb +34 -0
- data/lib/public/doc/mail/private.yaml +7 -0
- data/lib/public/doc/mail/swistak.jpeg +0 -0
- data/lib/public/images/kumkwat.jpg +0 -0
- data/lib/public/stylesheets/nosql.css +8 -0
- data/lib/views/blogi.rdiscount +5 -0
- data/lib/views/couchdb-couchapp.rdiscount +83 -0
- data/lib/views/couchdb-crud.rdiscount +205 -0
- data/lib/views/couchdb-futon.rdiscount +116 -0
- data/lib/views/couchdb-ruby.rdiscount +53 -0
- data/lib/views/couchdb-views.rdiscount +162 -0
- data/lib/views/couchdb.rdiscount +122 -0
- data/lib/views/main.rdiscount +55 -12
- data/lib/views/summary.rdiscount +52 -3
- data/lib/views/zadania.rdiscount +9 -0
- metadata +30 -6
@@ -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"
|