繁体   English   中英

有没有更简单的方法来使用 python 更新 MongoDB 中的整个记录​​?

[英]Is there a simpler way to update an entire record in MongoDB using python?

我的用例是这样的:我将一个 json 有效负载传递给一个 python 程序,该程序有条件地将记录插入到我的 MongoDB 集合中。 它检查集合记录中的唯一组合,如果“时间戳”更大,则更新记录,如果未找到组合,则更新记录,如果“时间戳”更低,则保留记录。

payload = {'stCode': 'ABC1', 'skCode': 'CDE2', 'batchCode': 'FGH3', ts: '2022/07/04 09:48:36'}
inp_ts = payload['ts']
inp_ts = datetime.strptime(inp_ts, '%Y/%m/%d %H:%M:%S')
inp_ts_iso = inp_ts.isoformat()

stCode = payload['stCode']
skCode = payload['skCode']
batchCode = payload['batchCode']
    
result = collection.find_one({'stCode': stCode,'skCode': skCode, 'batchCode': batchCode }) 

if result is None:
    collection.insert_one(payload) #Condition1: Insert record if not present
        
else:
    result_ts = result['ts']
    result_ts = datetime.strptime(result_ts, '%Y/%m/%d %H:%M:%S')
    result_ts_iso = result_ts.isoformat() #since the date is stored as string in the database
        
    if inp_ts_iso > result_ts_iso:
        temps={"storeCode": storeCode,"skuCode": skuCode, "batchCode": batchCode }, {"$set": payload}
        collection.update_one(*temps) #Condition2: Update record if timestamp is older
        print('Records successfully written to MongoDB')
            
    else:
        print("no records written") #Condition3: Do nothing if timestamp is newer

我知道它不是最漂亮的代码,但我希望它更简单、更简短。 有没有办法通过让 Lambda 进行逻辑测试而不是在 Mongo 本身进行测试来实现相同的目标? 我见过复杂的 update_one 查询,但我无法为我的利益工作。 提前致谢!

是的,您可以,您可以通过几种不同的方式进行操作,但它们都涉及使用流水线更新,这允许您在更新中使用聚合运算符。

这是我认为实现这一目标的最优雅的方法:(底部方法的摘要)

const payload = {'stCode': 'ABC1', 'skCode': 'CDE2', 'batchCode': 'FGH3', ts: '2022/07/04 09:48:36'}
const stCode = payload['stCode']
const skCode = payload['skCode']
const batchCode = payload['batchCode']

db.collection.updateOne(
    {'stCode': stCode,'skCode': skCode, 'batchCode': batchCode },
    [
      {
        "$replaceRoot": {
          "newRoot": {
            "$mergeObjects": [
              "$$ROOT",
              {
                $cond: [
                  {
                    $gt: [
                      "$ts",
                      payload.ts
                    ]
                  },
                  {},
                  payload
                ]
              }
            ]
          }
        }
      }
    ],
    {
      "upsert": true
    }
)

或使用pymongo

payload = {'stCode': 'ABC1', 'skCode': 'CDE2', 'batchCode': 'FGH3', ts: '2022/07/04 09:48:36'}
stCode = payload['stCode']
skCode = payload['skCode']
batchCode = payload['batchCode']

collection.update_one(
    {'stCode': stCode, 'skCode': skCode, 'batchCode': batchCode},
    [
        {
            "$replaceRoot": {
                "newRoot": {
                    "$mergeObjects": [
                        "$$ROOT",
                        {
                            "$cond": [
                                {
                                    "$gt": [
                                        "$ts",
                                        payload['ts']
                                    ]
                                },
                                {},
                                payload
                            ]
                        }
                    ]
                }
            }
        }
    ],
    upsert=True
)

蒙戈游乐场

所以我们在更新中使用$replaceRoot ,新的根是两个对象的合并。 第一个对象是$$ROOT参数,所以如果文档不存在它基本上是一个空对象,如果它确实存在那么它是原始对象,这背后的想法是第一个对象是保留_id字段(以及任何其他必需的预先存在的字段)可能存在于对象上,这就是为什么我们不只在$replaceRoot中使用新对象,因为它会生成一个新的_id

第二个对象基于使用$cond的条件,如果现有的ts更大,那么我们使用一个空对象,它不会更改原始$$ROOT ,否则我们只使用新的有效负载,它将覆盖任何现有字段. 如前所述,如果新的有效负载缺少字段,如果可能需要进行一些小的更改,它们将不会被覆盖,但是根据您的代码示例,未处理此潜在的边缘情况,因此我认为它不存在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM