python - 使用 Python Eve 添加 mongoDB 文档数组元素

标签 python mongodb rest eve

背景:(使用 Eve 和 Mongo)

我正在使用 Python 使用 Eve REST 提供程序库连接并连接到 mongoDB 以从数据库公开许多 REST 端点。到目前为止,我在使用 Eve 时运气不错,但我遇到了一个问题,这可能超出了 Eve 本身所能做的范围。

我的问题是我的 mongoDb 文档格式有一个字段(称为“插槽”),其值是字典/嵌入文档的列表/数组。

所以mongoDB的文档结构是:

{
   blah1: data1,
   blah2: data2,
   ...
   slots: [
       {thing1:data1, thing2:data2},
       {thingX:dataX, thingY:dataY}
   ]
}

我需要将新记录(即添加预填充的字典)添加到“插槽”列表中。

如果我想象直接通过 pymongo 进行插入,它看起来像:

mongo.connection = MongoClient()
mongo.db = mongo.connection['myDB']
mongo.coll = mongo.db['myCollection']

...

mongo.coll.update({'_id' : document_id}, 
                  {'$push': { "slot" : {"thing1":"data1","thingX":"dataX"}  }  } )

我想要执行此操作的 REST 操作/URI 组合是到“_id/slots”的 POST,例如/app/012345678901234567890123/slots的URI。

问题:(在 Eve 中将元素插入到数组中)

从 SO:How to add to a list type in Python Eve without replacing old valueseve project issue 看来,Eve 目前不支持对 mongoDB 嵌入式文档(或数组?)进行操作,除非整个嵌入式文档被重写,并且在我的情况下重写整个数组是非常不可取的。


所以,假设它真正的 Eve 没有允许插入数组元素的方法(并且鉴于我已经有许多其他端点在 Eve 内部运行良好)...


...我现在正在寻找一种方法,在具有多个工作端点的 Eve/Flask 配置中,仅为这个端点拦截和更改 Eve 的 mongoDB 写入。

我知道(最坏的情况)我可以覆盖 Eve 的路由并完​​全手动编写,但是我会管理 _updated 并手动检查和更改文档 _etag 值,我当然不希望为此编写新代码。

我查看了 Eve 的 Datebase event hooks,但没有看到修改执行的数据库命令的方法(我可以看到如何更改 data,但不能更改 commands )。

其他人已经解决了这个问题吗?如果没有关于手动实现的最直接路径的任何想法? (希望尽可能多地重用 Eve,因为我确实想继续将 Eve 用于我所有(已经工作的)端点)

最佳答案

这是一个有趣的问题。我相信,为了实现您的目标,您需要执行两项操作:

  1. 构建并传递自定义验证器。
  2. 构建并传递自定义 Mongo 数据层。

这听起来可能工作量太大,但可能并非如此。


自定义验证器

将需要一个自定义验证器,因为当您在“启用推送”的端点上执行 PATCH 请求时,您希望传递一个在语法上与端点验证模式不同的文档。您将传递一个 dict ({"slot": {"thing1": "data1", "thingX": "dataX"}}) 而端点需要一个列表:

'mycollection': {
    'type': 'list',
    'schema': {
        'type': 'dict',
        'schema': {
            'thing1': {'type': 'string'},
            'thingX': {'type': 'string'},
        }
    }
}

如果您不自定义验证,最终会出现验证错误(list type expected)。我猜您的自定义验证器可能类似于:

from eve.data.mongo.validation import Validator
from flask import request

class MyValidator(Validator):
    def validate_replace(self, document, _id, original_document=None):
        if self.resource = 'mycollection' and request.method = 'PATCH':
            # you want to perform some real validation here
            return True
        return super(Validator, self).validate(document)

请注意,我没有尝试此代码,因此可能需要在这里和那里进行一些调整。

另一种方法是为 PATCH 请求设置一个替代端点。该端点将使用相同的数据源并具有类似字典的模式。这将避免对自定义验证器的需求,而且您仍然可以在标准端点上进行正常的原子字段更新 ($set)。实际上,我认为我更喜欢这种方法,因为您不会失去功能并降低复杂性。有关访问同一数据源的多个端点的指南,请参阅 the docs


自定义数据层

这是必需的,因为当 mycollection 涉及 PATCH 请求时,您希望执行 $push 而不是 $set。可能是这样的:

from eve.io.mongo import Mongo
from flask import request

class MyMongo(Mongo):
    def update(self, resource, id_, updates, original):
        op = '$push' if resource == 'mycollection' else '$set'
        return self._change_request(resource, id_, {op: updates}, original)

把它们放在一起

然后您在应用初始化时使用您的自定义验证器和数据层:

app = Eve(validator=MyValidator, data=MyMongo)
app.run()

我再次没有测试所有这些;今天是星期天,我在海滩上,所以它可能需要一些工作,但它应该工作。

话虽如此,我实际上将尝试向标准 Mongo 数据层添加对推送更新的支持。一对新的全局/端点设置,如 MONGO_UPDATE_OPERATOR/mongo_update_operator 在私有(private)分支上实现。前者默认为 $set 所以所有 API 端点仍然执行原子字段更新。可以决定某个端点应该执行其他操作,比如 $push。以一种简洁优雅的方式实现验证有点棘手,但假设我有时间研究它,这不太可能让它达到 Eve 0.6 或更高版本。

希望这会有所帮助。

关于python - 使用 Python Eve 添加 mongoDB 文档数组元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30537070/

相关文章:

javascript - 使用 IntelliJ IDEA for JavaScript 的最佳插件和项目?

python - 使用 MongoEngine 自动增量

java - 无法在 netbeans 7.3.1 中使用 Jersey 特定功能

angularjs - AngularJS中的全局错误处理

python - 为什么 scipy.optimize 如此依赖起始值?

python - django.db.utils.ProgrammingError : cannot cast type text[] to jsonb

mongodb - pymongo 删除/更新命令返回

android - 具有自动完成功能的不同步 ArrayAdapter

Python - 阶乘之和

python - 排除要抓取的元素