【问题标题】:MongoDB push to nested array or insert new documentMongoDB推送到嵌套数组或插入新文档
【发布时间】:2020-03-27 12:26:52
【问题描述】:

我正在使用 Python 的 Mongo 库 (pymongo),我的文档如下所示:

{"vendor_id": 12, "title": "xyz", "price": 1499.0, "price_history": [{"date": "2019-12-01", "price": 1890.0}]}

如果存在 id=12 的文档,我想将新的价格对象推送到“price_history”数组。如果不是,我将创建一个与粘贴代码看起来相同的新文档。

看起来很简单,但我检查了多个 stackoverflow 主题和 mongodb 文档,但无法得到它:/

我想出了代码:

db.holidays.update_one(
            {"vendor_id": t["vendor_id"]},
            {"$push": {"price_history": t["price_history"][0]}},
            upsert=True
        )

但是当找不到文档时,它只插入 vendor_id 而不是整个文档。

有什么建议吗? 感谢您花时间解决我的问题。

【问题讨论】:

  • 当您说 ...看起来与上面粘贴的代码相同... 是否意味着新文档将具有相同的 vendor_id 值,@ 987654324@、price等字段?
  • 是的,我的意思是它只会将整个文档插入到集合中。我正在阅读有关 $setOnInsert 的信息 - 也许这就是我应该走的路?
  • $setOnInsert 正是要走的路。

标签: python mongodb mongodb-query pymongo upsert


【解决方案1】:

$setOnInsert 救援:

db.holidays.update(
   { "vendor_id": t["vendor_id" },   // Query parameter
   ,{                     // Update document
      "$push": {"price_history": t["price_history"][0]},
      "$setOnInsert": { everything else you want insert besides the push and the vendor_id
   }
   ,{ upsert: true }      // Options
)

【讨论】:

    【解决方案2】:

    将记录提取到 dict 中并使用标准 python 进行操作。如果您使用find_one() 并且没有匹配项,它将返回None

    from pymongo import MongoClient
    from bson.json_util import dumps
    
    db = MongoClient()["testdatabase"]
    
    # Data setup
    db.testcollection.delete_many({})
    template = {"vendor_id": 12, "title": "xyz", "price": 1499.0, "price_history": []}
    data_setup = {"vendor_id": 12, "title": "xyz", "price": 1499.0,
                  "price_history": [{"date": "2019-12-01", "price": 1890.0}]}
    new_price = {"date": "2019-12-02", "price": 2000.0}
    
    # Comment the next line out to see what happens if the record isn't present
    db.testcollection.insert_one(data_setup)
    
    record = db.testcollection.find_one({"vendor_id": 12})
    if record is None:
        record = template
    
    record['price_history'].append(new_price)
    db.testcollection.replace_one({"vendor_id": 12}, record, upsert=True)
    
    # Pretty up the record output
    print(dumps(db.testcollection.find_one({}, {'_id': 0}), indent=4))
    

    给予:

    {
        "vendor_id": 12,
        "title": "xyz",
        "price": 1499.0,
        "price_history": [
            {
                "date": "2019-12-01",
                "price": 1890.0
            },
            {
                "date": "2019-12-02",
                "price": 2000.0
            }
        ]
    }
    

    【讨论】:

    • 感谢您的解决方案,我对此表示赞同,但我认为对数据库的请求有点过多,不想为此付费:D
    • 去掉设置后只有 2 个调用。确保将索引添加到 vendor_id,除非您进行数百万次更新,否则它会非常快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多