RethinkDB:​​如何动态构建合并查询?

时间:2014-02-18 12:47:16

标签: python merge rethinkdb rethinkdb-python

我正在使用Python Flask构建API。我喜欢在RethinkDB上编写合并查询的简便性。更好的是,我注意到可以编写一个薄层来编写关于用户输入的动态合并查询。

假设我们正在构建一个聊天应用。以下是示例代码:https://github.com/dogukantufekci/rethinkdb_dynamic_merge

表格和字段:

  1. 帐户:“id”,“created_on”,“name”,“email”,“password”
  2. 对话:“id”,“created_on”,“subject”,“to”(与会者名单)
  3. 消息:“id”,“created_on”,“text”,“conversation”,“from”
  4. message_readers:“id”,“message”,“reader”
  5. 查询合并所有4个表:

    r.table("accounts").map(lambda account: 
        account.merge({
            "conversations": r.table("conversations").filter(lambda conversation: 
                conversation["to"].contains(account["id"])).coerce_to("array").map(lambda conversation:
                conversation.merge({
                    "to": conversation["to"].map(lambda account: 
                        r.table("accounts").get(account)).coerce_to("array"),
                    "messages": r.table("messages").filter(lambda message:
                        message["conversation"] == conversation["id"]).coerce_to("array").map(lambda message:
                        message.merge({
                            "from": r.table("accounts").get(message["from"]),
                            "readers": r.table("message_readers").filter(lambda readers:
                                readers["message"] == message["id"]).coerce_to("array"),
                        }))
                }))
        })).run(g.db_connection)
    

    结果:

    [{
        "id": "account111",
        "created_on": 1392515093.252,  
        "name": "John Doe",
        "email": "john@doe.com",
        "conversations": [
            {
                "id": "conversation111",
                "created_on": 1392515093.252,  
                "subject": "Merging Queries on RethinkDB",
                "to": [
                    {
                        "id": "account111",
                        "created_on": 1392515093.252,  
                        "name": "John Doe", 
                        "email": "john@doe.com", 
                    }, 
                    {
                        "id": "account222",
                        "created_on": 1392515604.123,  
                        "name": "Mark Bobby", 
                        "email": "mark@bobby.com", 
                    }, 
                ], 
                "messages": [
                    {
                        "id": "message111",
                        "created_on": 1392515604.123,  
                        "text": "How do we dynamically build merge queries?", 
                        "conversation": "conversation111", 
                        "from": {
                            "id": "account111",
                            "created_on": 1392515093.252,  
                            "name": "John Doe",
                            "email": "john@doe.com",
                        }, 
                        "readers": [
                            {
                                "id": "message_reader111", 
                                "created_on": 1392515604.123, 
                                "message": "message111",
                                "reader": "account111",
                            }, 
                            {
                                "id": "message_reader222", 
                                "created_on": 1392515604.123, 
                                "message": "message111",
                                "reader": "account222",
                            },
                        ],
                    },
                ], 
            }, 
        ],        
    }]
    

    到目前为止很棒!

    更简单的回复需要通过对话返回帐户数据;没有消息:

    [{
        "id": "account111",
        "created_on": 1392515093.252,  
        "name": "John Doe",
        "email": "john@doe.com",
        "conversations": [
            {
                "id": "conversation111",
                "created_on": 1392515093.252,  
                "subject": "Merging Queries on RethinkDB",
                "to": [
                    {
                        "id": "account111",
                        "created_on": 1392515093.252,  
                        "name": "John Doe", 
                        "email": "john@doe.com", 
                    }, 
                    {
                        "id": "account222",
                        "created_on": 1392515604.123,  
                        "name": "Mark Bobby", 
                        "email": "mark@bobby.com", 
                    }, 
                ], 
            }, 
        ],        
    }]
    

    有两种方法可以获得此结果:

    1. 我们可以重新编写一个查询:

      r.table("accounts").map(lambda account: 
          account.merge({
              "conversations": r.table("conversations").filter(lambda conversation: 
                  conversation["to"].contains(account["id"])).coerce_to("array").map(lambda conversation:
                  conversation.merge({
                      "to": conversation["to"].map(lambda account: 
                          r.table("accounts").get(account)).coerce_to("array"),
                  }))
          })).run(g.db_connection)
      

      缺点:如果需要为替代字段组合创建进一步的查询,这不是最佳实践,因为它不是动态的并且有很多重复。

    2. 我们可以使用pluck修改大查询的最后一行来选择字段:

      })).pluck(["id", "created_on", "name", "email", {"conversations": ["id", "created_on", "subject", {"to": ["id", "created_on", "name", "email"]}]}]).run(g.db_connection)
      

      优势:它是动态的,因为它使用户能够通过URL

      获取值作为参数
      http://www.myproject.com/accounts/?pluck=["id", "created_on", "name", "email", {"conversations": ["id", "created_on", "subject", {"to": ["id", "created_on", "name", "email"]}]}]
      

      缺点:查询确实消耗了大量的计算能量来合并我们在最终结果中不需要的表。

    3. 因此,挑战在于通过接受来自用户的pluck值来动态构建查询。

      您可以轻松注意到两种惯例:

      1. 每个dict字段都有一个接受dict对象的查询:

        "messages": r.table("messages").filter(lambda message:
            message["conversation"] == conversation["id"]).coerce_to("array").map(lambda message:
                message.merge({})
        
      2. 每个非dict字段都有一个独立的查询:

        "from": r.table("accounts").get(message["from"])
        
      3. 那么我们如何才能使用所有这些信息并构建我们良好的动态合并查询?

1 个答案:

答案 0 :(得分:1)

我的建议是放弃动态部分。相反,您应该以RESTful方式设计API。这意味着,对于您的示例,如果有人想要访问帐户,他们可以向/ accounts / [identifier]发送GET请求。如果您想要发送或接收帐户的所有邮件,他们会向/ accounts / [identifier] / messages发送GET请求。

另外,为什么需要会话对象?我会按如下方式更改您的数据库结构:

  1. 帐户:“id”,“created_on”,“name”,“email”,“password” - 不变
  2. 对话: - 已删除
  3. 消息:“id”,“created_on”,“text”,“sender”,“receiver”
  4. message_readers: - 已删除