gpt4 book ai didi

python - 使用 Python 基于来自用户的 JSON 构建 mongoDB 查询

转载 作者:可可西里 更新时间:2023-11-01 09:25:15 26 4
gpt4 key购买 nike

我需要一个用于 mongodb 的自定义查询构建器。我已经完成了可用于查询的文档(字段)列表的用户界面。用户可以选择“结果列”、“条件”、“分组依据”和“排序依据”。让我用 SQL 语言来解释。看例子:

SELECT col1, col2 FROM table WHERE col1=1 AND col2="foo" OR col3 > "2012-01-01 00:00:00" OR col3 < "2012-01-02 00:00:00" AND col5 IN (100, 101, 102) GROUP BY col4, col5 ORDER BY col1 DESC, col2 ASC

所以

  • SELECT col1, col2 -- 结果列
  • WHERE col1=1 AND col2="foo"OR col3 > "2012-01-01 00:00:00"OR col3 < "2012-01-02 00:00:00"-- 条件
  • GROUP BY col4, col5 -- 分组语句
  • ORDER BY col1 DESC, col2 ASC -- 按语句排序

列计数、条件、分组依据和排序依据应由 Python 根据用户界面提交的 JSON 数据生成。

我很好奇是否可以使用 MapReduce 为 mongoDB 做这件事?也许你看到了任何模块?另外,如果您擅长 MongoDB,能否将此 SQL 查询转换为 MongoDB 查询?

最佳答案

最简单(也是最具可扩展性)的解决方案可能是将过滤条件转换为 MongoDB 查询,并在客户端进行聚合。

以上面的示例为例,让我们将其分解并构建一个 MongoDB 查询(我将使用 PyMongo 来展示它,但如果您愿意,您也可以使用 Mongoengine 或其他 ODM 来执行相同的操作):

WHERE col1=1 AND col2="foo" OR col3 > "2012-01-01 00:00:00" OR col3 < "2012-01-02 00:00:00" -- conditions

这是 PyMongo 的 find() 方法的第一个参数。我们必须使用 $or 运算符显式构建逻辑 AND/OR 树:

from bson.tz_util import utc
cursor = db.collection.find({'$or': [
{'col1': 1, 'col2': 'foo'},
{'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
{'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]})

请注意,在与日期/时间字段进行比较时,MongoDB 不会将字符串转换为日期,所以我在这里使用 Python datetime 明确地这样做了模块。 datetime该模块中的类假定 0 作为非指定参数的默认值。

SELECT col1, col2 -- result columns

我们可以使用field selection只检索我们想要的字段:

from bson.tz_util import utc
cursor = db.collection.find({'$or': [
{'col1': 1, 'col2': 'foo'},
{'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
{'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}, fields=['col1', 'col2'])

GROUP BY col4, col5 -- group by statement

使用标准 MongoDB 查询无法有效地完成此操作(不过稍后我将展示您如何使用新的 Aggregation Framework 在服务器端完成所有这些操作)。相反,知道我们想要按这些列分组,我们可以通过按这些字段排序来简化应用程序代码:

from bson.tz_util import utc
from pymongo import ASCENDING
cursor = db.collection.find({'$or': [
{'col1': 1, 'col2': 'foo'},
{'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
{'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}, fields=['col1', 'col2', 'col4', 'col5'])
cursor.sort([('col4', ASCENDING), ('col5', ASCENDING)])

ORDER BY col1 DESC, col2 ASC -- order by statement

这应该在应用您想要的聚合函数后在您的应用程序代码中完成(假设我们想要对 col4 求和,并取 col5 的最大值):

from bson.tz_util import utc
from pymongo import ASCENDING
cursor = db.collection.find({'$or': [
{'col1': 1, 'col2': 'foo'},
{'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
{'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}, fields=['col1', 'col2', 'col4', 'col5'])
cursor.sort([('col4', ASCENDING), ('col5', ASCENDING)])

# groupby REQUIRES that the iterable be sorted to work
# correctly; we've asked Mongo to do this, so we don't
# need to do so explicitly here.
from itertools import groupby
groups = groupby(cursor, keyfunc=lambda doc: (doc['col1'], doc['col2'])
out = []
for (col1, col2), docs in groups:
col4sum = 0
col5max = float('-inf')
for doc in docs:
col4sum += doc['col4']
col5max = max(col5max, doc['col5'])
out.append({
'col1': col1,
'col2': col2,
'col4sum': col4sum,
'col5max': col5max
})

使用聚合框架

如果您使用的是 MongoDB 2.1 或更高版本(2.1.x 是即将发布的 2.2.0 稳定版本的开发系列),您可以使用聚合框架在服务器端完成所有这些工作。为此,请使用 aggregate 命令:

from bson.son import SON
from pymongo import ASCENDING, DESCENDING
group_key = SON([('col4', '$col4'), ('col5': '$col5')])
sort_key = SON([('$col1', DESCENDING), ('$col2', ASCENDING)])
db.command('aggregate', 'collection_name', pipeline=[
# this is like the WHERE clause
{'$match': {'$or': [
{'col1': 1, 'col2': 'foo'},
{'col3': {'$gt': datetime(2012, 01, 01, tzinfo=utc)}},
{'col3': {'$lt': datetime(2012, 01, 02, tzinfo=utc)}},
]}},
# SELECT sum(col4), max(col5) ... GROUP BY col4, col5
{'$group': {
'_id': group_key,
'col4sum': {'$sum': '$col4'},
'col5max': {'$max': '$col5'}}},
# ORDER BY col1 DESC, col2 ASC
{'$sort': sort_key}
])

aggregate 命令返回一个 BSON 文档(即 Python 字典),它受到 MongoDB 的通常限制:如果要返回的文档的大小大于 16MB,它将失败。此外,对于内存中排序(如此聚合末尾的 $sort 所要求),如果排序需要服务器上超过 10% 的物理 RAM,则聚合框架将失败(这是为了防止代价高昂的聚合驱逐 Mongo 用于数据文件的所有内存)。

关于python - 使用 Python 基于来自用户的 JSON 构建 mongoDB 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10209863/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com