世界中に道はありませんが、人が歩けば歩くほど道は増えます。なぜPostgres上でMongoDBを構築できないのですか?
Postgresコミュニティは、NoSQLの一連の動きの後でもじっとしていません。 PLV8はV8 Javascriptエンジンを導入しています。 JSONの操作がより簡単になりました。
始める前に必要なこと
MongoDB の最下層はコレクションです。 コレクションはテーブルとして表現できます。
CREATE TABLE some_collection (
some_collection_id SERIAL NOT NULL PRIMARY KEY,
data JSON
);
文字ベースのJSONはPostgresのテーブルに保存されます。
以下の実装では、コレクションが自動的に作成されます。 コレクションテーブルに保存されます。
CREATE TABLE collection (
collection_id SERIAL NOT NULL PRIMARY KEY,
name VARCHAR
);
-- make sure the name is unique
CREATE UNIQUE INDEX idx_collection_constraint ON collection (name);
テーブルが作成されると、コレクションはストアドプロシージャによって自動的に作成されます。 これを行うには、まずテーブルを作成し、次にテーブルシーケンスを挿入します。
CREATE OR REPLACE FUNCTION create_collection(collection varchar) RETURNS
boolean AS $$
var plan1 = plv8.prepare('INSERT INTO collection (name) VALUES ($1)', [ 'varchar' ]);
var plan2 = plv8.prepare('CREATE TABLE col_' + collection +
' (col_' + collection + '_id INT NOT NULL PRIMARY KEY, data JSON)');
var plan3 = plv8.prepare('CREATE SEQUENCE seq_col_' + collection);
var ret;
try {
plv8.subtransaction(function () {
plan1.execute([ collection ]);
plan2.execute([ ]);
plan3.execute([ ]);
ret = true;
});
} catch (err) {
ret = false;
}
plan1.free();
plan2.free();
plan3.free();
return ret;
$$ LANGUAGE plv8 IMMUTABLE STRICT;
ストアドプロシージャを使えば、以下のことが簡単になります。
SELECT create_collection('my_collection');
コレクションストレージの問題を解決したので、次は MongoDB のデータ解析を見てみましょう。 MongoDB は、ポイントアノテーションメソッドでこれを実現します。
CREATE OR REPLACE FUNCTION find_in_obj(data json, key varchar) RETURNS
VARCHAR AS $$
var obj = JSON.parse(data);
var parts = key.split('.');
var part = parts.shift();
while (part && (obj = obj[part]) !== undefined) {
part = parts.shift();
}
// this will either be the value, or undefined
return obj;
$$ LANGUAGE plv8 STRICT;
上記の関数はVARCHARを返します。これはすべての場合に適しているわけではありませんが、文字列の比較には便利です。
SELECT data
FROM col_my_collection
WHERE find_in_obj(data, 'some.element') = 'something cool'
文字列の比較だけでなく、MongoDB では exists キーワードを使った数値型の比較も提供しています。 以下に find_in_obj() メソッドのさまざまな実装を示します。
CREATE OR REPLACE FUNCTION find_in_obj_int(data json, key varchar) RETURNS
INT AS $$
var obj = JSON.parse(data);
var parts = key.split('.');
var part = parts.shift();
while (part && (obj = obj[part]) !== undefined) {
part = parts.shift();
}
return Number(obj);
$$ LANGUAGE plv8 STRICT;
CREATE OR REPLACE FUNCTION find_in_obj_exists(data json, key varchar) RETURNS
BOOLEAN AS $$
var obj = JSON.parse(data);
var parts = key.split('.');
var part = parts.shift();
while (part && (obj = obj[part]) !== undefined) {
part = parts.shift();
}
return (obj === undefined ? 'f' : 't');
$$ LANGUAGE plv8 STRICT;
次のステップは、データのクエリです。 find() メソッドは既存の素材を使用して実装されています。
#p#
このセクションでは、データの保存と MongDB クエリから WHERE 句を作成し、書き込まれたデータを取得する方法について説明します。
コレクションへのデータの保存は簡単です。まず、JSONオブジェクトを検査し、_id値を探す必要があります。コードのこの部分は、_idがすでに存在する場合は更新を意味し、そうでない場合は挿入を意味することをネイティブに想定しています。objectIDはまだ作成されていないことに注意してください:
CREATE OR REPLACE FUNCTION save(collection varchar, data json) RETURNS
BOOLEAN AS $$
var obj = JSON.parse(data);
var id = obj._id;
// if there is no id, naively assume an insert
if (id === undefined) {
// get the next value from the sequence for the ID
var seq = plv8.prepare("SELECT nextval('seq_col_" +
collection + "') AS id");
var rows = seq.execute([ ]);
id = rows[0].id;
obj._id = id;
seq.free();
var insert = plv8.prepare("INSERT INTO col_" + collection +
" (col_" + collection + "_id, data) VALUES ($1, $2)",
[ 'int', 'json']);
insert.execute([ id, JSON.stringify(obj) ]);
insert.free();
} else {
var update = plv8.prepare("UPDATE col_" + collection +
" SET data = $1 WHERE col_" + collection + "_id = $2",
[ 'json', 'int' ]);
update.execute([ data, id ]);
}
return true;
$$ LANGUAGE plv8 IMMUTABLE STRICT;
この考えに基づいて、挿入のための簡単な文書をいくつか作成することができます:
{
"name": "Jane Doe",
"address": {
"street": "123 Fake Street",
"city": "Portland",
"state": "OR"
},
"age": 33
}
{
"name": "Sarah Smith",
"address": {
"street": "456 Real Ave",
"city": "Seattle",
"state": "WA"
}
}
{
"name": "James Jones",
"address": {
"street": "789 Infinity Way",
"city": "Oakland",
"state": "CA"
},
"age": 23
}
コレクションを作成し、データを挿入します:
work=# SELECT create_collection('data');
create_collection
-------------------
t
(1 row)
work=# SELECT save('data', '{ our object }');
save
------
t
(1 row)