blog

PostgresでMongoDBをクローンする

NoSQLによる一連の動きの後、Postgresコミュニティはじっとしていませんでした。 PostgresはJSONとPLV8の統合を進めています。 PLV8はV8エンジンを導入しています。 JSO...

Mar 23, 2025 · 7 min. read
シェア

世界中に道はありませんが、人が歩けば歩くほど道は増えます。なぜ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) 
Read next

OpenSSL「Heartbleed」脆弱性の分析

OpenSSL "Heartbleed" 脆弱性は非常に深刻な問題です。この脆弱性により、攻撃者はメモリから最大64KBのデータを読み取ることができます。

Mar 23, 2025 · 6 min read