我正在使用 Python Flask 构建一个 API。我喜欢在 RethinkDB 上轻松编写合并查询。更好的是,我注意到可以编写一个薄层来编码关于用户输入的动态合并查询。
假设我们正在构建一个聊天应用程序。这是示例代码:https ://github.com/dogukantufekci/rethinkdb_dynamic_merge
表格和字段:
- 帐户:“id”、“created_on”、“名称”、“电子邮件”、“密码”
- 对话:“id”、“created_on”、“subject”、“to”(参与者列表)
- 消息:“id”、“created_on”、“text”、“conversation”、“from”
- message_readers: "id", "message", "reader"
查询以合并所有 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",
},
],
},
],
}]
有两种方法可以得到这个结果:
我们可以重写一个查询:
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)
缺点:如果需要为替代字段组合创建更多查询,这不是最佳实践,因为它不是动态的并且有很多重复。
我们可以用 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"]}]}]
缺点:查询确实会消耗大量计算能量来合并我们在最终结果中不需要的表。
因此,挑战是通过接受用户的 pluck 值来动态构建查询。
您可以很容易地注意到两个约定:
每个 dict 字段都有一个接受 dict 对象的查询:
"messages": r.table("messages").filter(lambda message: message["conversation"] == conversation["id"]).coerce_to("array").map(lambda message: message.merge({})
每个非 dict 字段都有一个独立的查询:
"from": r.table("accounts").get(message["from"])
那么我们如何使用所有这些信息并构建我们漂亮的动态合并查询呢?