Python-Eve:防止在不使用唯一字段的情况下插入重复项

时间:2015-12-13 00:55:16

标签: python duplicates eve objectid

我试图通过以下方法阻止插入重复文档:

  1. 从所需端点获取所有文档的列表,该端点将包含JSON格式的所有文档。此列表名为available_docs
  2. 使用pre_POST_<endpoint>挂钩以便在插入数据之前处理请求。我没有使用on_insert挂钩,因为我需要在验证之前执行此操作。
  3. 由于我们可以访问request对象使用request.json来获取有效负载JSON格式
  4. 检查request.json
  5. 中是否已包含available_docs
  6. 如果新文件不是重复文件,则插入新文件,否则中止。
  7. 使用这种方法,我得到了以下片段:

    def check_duplicate(request):
        if not request.json in available_sims:
            print('Not a duplicate')
        else:
            print('Duplicate')
            flask.abort(422, description='Document is a duplicate and already in database.')
    

    available_docs列表如下所示:

    available_docs = [{'foo': ObjectId('565e12c58b724d7884cd02bb'), 'bar': [ObjectId('565e12c58b724d7884cd02b9'), ObjectId('565e12c58b724d7884cd02ba')]}]
    

    有效负载request.json如下所示:

    {'foo': '565e12c58b724d7884cd02bb', 'bar': ['565e12c58b724d7884cd02b9', '565e12c58b724d7884cd02ba']}
    

    如您所见,传递给API的文档与已存储在DB中的文档之间的唯一区别是ID的数据类型。由于这个事实,我上面代码段中的if - 语句评估为True,并判断要插入的文档不是重复文件,而它肯定是重复文件。

    有没有办法检查传递的文档是否已经存在于数据库中?我无法使用唯一字段,因为所有文档字段的组合只需要是唯一的。有一个唯一的标识符(我在本例中省略了),但这不适合所需的比较,因为它是一种时间戳。​​

    我认为像键foobar那样将ObjectIDs的给定ID转换成ObjectID就行了,但我不知道如何处理这个问题,因为我不知道从哪里获取数据类型{{1}}。

2 个答案:

答案 0 :(得分:1)

您的方法比为字段设置唯一规则要慢

因为从你的例子中,你要比较objectids,你不能简单地将它们用作集合的_id字段吗?在Mongo(当然还有Eve)中,该字段默认是唯一的。实际上,您通常甚至不定义它。您根本不需要做任何事情,因为具有已存在ID的文档的POST会立即失败。

如果你不能这样做(也许你需要比较一个不同的objectid字段,但由于某种原因,你不能简单地为该字段设置unique规则),我会看一下查询db以获取字段值,而不是从db获取所有文档,然后在代码中按顺序扫描它们。像db.find({db_field: new_document_field_value})这样的东西。如果返回true,则新文档是重复的。确保将db_field编入索引(对于标有unique规则的字段,通常也适用)

评论后编辑。一个简单的实现很可能是这样的:

def pre_POST_callback(resource, request):
    # retrieve mongodb collection using eve connection
    docs = app.data.driver.db['docs']

    if docs.find_one({'foo': <value>}):
        flask.abort(422, description='Document is a duplicate and already in database.')


app = Eve()
app.run()

答案 1 :(得分:1)

这是我防止重复记录的方法:

def on_insert_subscription(items): c_subscription = app.data.driver.db['subscription'] user = decode_token() if user: for item in items: if c_subscription.find_one({ 'topic': ObjectId(item['topic']), 'client': ObjectId(user['user_id']) }): abort(422, description="Client already subscribed to this topic") else: item['client'] = ObjectId(user['user_id']) else: abort(401, description='Please provide proper credentials')

我在这里做的是为客户创建订阅。如果客户已经订阅了我扔422的主题。 注意:客户端ID是从JWT令牌解码的。