在 Postgres 里克隆一个 MongoDB :第二部分 已翻译 100%

FreeZ 投递于 2014/04/21 23:08 (共 2 段, 翻译完成于 04-29)
阅读 2243
收藏 44
2
加载中

第一部分中我们讨论了创建集合和JSON对象一插入时的深度检测。在本部分中将覆盖保存数据以及从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)

你可以通过检查“col_data”表的内容来查看对象。

Garfielt
翻译于 2014/04/22 11:32
1

现在我们已经有了一些数据,让我们再查询一下。假设我们想查找住在俄勒冈或华盛顿州年龄大于30的所有人,使用一个MongoDB风格的find():

    {
      "$or": [
        {
          "address.state": "OR"
        },
        {
          "address.state": "WA"
        }
      ],
      "age": {
        "$gt": 30
      }
    }

因为上次我们已经创建了一些深度的包检测,现在就很容易创建查询并返回Jane Doe:

    SELECT data
      FROM col_data
     WHERE find_in_obj_int(data, 'age') > 30
       AND (
             find_in_obj(data, 'address.state') = 'OR'
           OR
             find_in_obj(data, 'address.state') = 'WA'
           )

我采用了写一个递归调用函数来建立WHERE子句的方法。它有点长,所以我没有把它贴在这里而是放在GitHub上。一旦find()存储过程被创建,我们就可以在查询中使用它。我们应该能够看到Jane Doe被返回:

    work=# SELECT find('data', '{ "$or": [ { "address.state": "OR" }, { "address.state": "WA" } ], "age": { "$gt": 30 } }');

这样奏效:它不优雅,但它奏效。这是一个概念的证明,而且几乎没有像它一样好的可能。我之前曾被问过为什么不使用HSTORE。虽然你可以存储嵌套的HSTORE和数组值,但它仍不是JSON,并且不容易通过PLV8操作。这将需要一个从HSTORE到JSON的序列器,这个序列器在任何时间将请求的返回序列化成MongoDB接受的数据形式,但依旧太容易在JavaScript中处理。这是次优选择,毕竟我们是要在Postgres的基础上创建一个MongoDB的副本。

源码可以在GitHub上找到:fork并尝试一下吧,记得回馈哦。

Garfielt
翻译于 2014/04/22 17:17
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(4)

FreeZ
FreeZ

@红薯 第二段为什么丢了?

老码农

同等性能测试报告

jobell
jobell

有没有做过性能测试呢?希望能够看到性能结果报告。

FreeZ
FreeZ

源码:https://github.com/JerrySievert/mongolike

返回顶部
顶部