MongoDB中的位置更新

2024-09-29 05:29:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试更新MongoDB中的一系列子文档。我知道位置运算符$不支持单个查询中的多个更新。你知道吗

示例文档:

{
  "_id": ObjectId("559a6c281816ba598cdf96cd"),
  "collections": [
    {
      "id": 12,
      "name": "a"
    },
    {
      "id": 12,
      "name": "b"
    }
  ]
}

我需要用一个额外的字段"price" : 12更新id : 12子文档。我尝试了下面的查询,但是匹配的子文档正在更新,因此我添加了一个额外的条件"price" : {$exists : false},还尝试了"price" : {$ne : 12}。当我添加"price" : {$exists : false}时,不会返回任何文档。我用的是PyMongo和python。所以我需要在python代码中执行更新并更新文档。有什么解决办法吗?你知道吗

已尝试查询:

db.scratch.update({ "collections.id" : 12 } , {"$set" : {"collections.$.price" : 12 }})

用上面的price : falseprice: {$exists : false}组合尝试过,但也不起作用。但我一直收到一个消息,一个文件被更新了。我在我的mongo shell中使用mongo hacker。你知道吗

我正在构建一个迁移工具,其中所有客户信息都作为单个文档显示。你知道吗

{
  "_id": ObjectId("559a2d9bfffe043444c72889"),
  "age": NumberLong("23"),
  "customer_address": [
    {
      "type": "Work",
      "verified": true,
      "address": "1A NY"
    }
  ],
  "customer_id": NumberLong("3"),
  "customer_orders": [
    {
      "order_date": ISODate("2015-01-01T00:12:01Z"),
      "order_id": NumberLong("2"),
      "product_id": NumberLong("234")
    },
    {
      "order_date": ISODate("2015-12-01T00:00:00Z"),
      "order_id": NumberLong("3"),
      "product_id": NumberLong("245")
    },
    {
      "order_date": ISODate("2015-12-21T00:00:00Z"),
      "order_id": NumberLong("4"),
      "product_id": NumberLong("267")
    },
    {
      "order_id": NumberLong("5"),
      "order_date": ISODate("2015-12-29T00:00:00Z"),
      "product_id": NumberLong("289")
    },
    {
      "order_id": NumberLong("9"),
      "order_date": ISODate("2015-02-01T00:12:05Z"),
      "product_id": NumberLong("234")
    }
  ]
}

我从customer表中获取基本信息,从customer address表中获取地址,从MySQL中通过外键引用关联的另一个表中获取产品日志。现在我想用正确的名称和价格更新产品id,这样我就可以查看客户,而不是通过查询来获取产品id的相应价格,而且因为join在中不存在

{
  "_id": ObjectId("559a2d9bfffe043444c72889"),
  "age": NumberLong("23"),
  "customer_address": [
    {
      "type": "Work",
      "verified": true,
      "address": "1A NY"
    }
  ],
  "customer_id": NumberLong("3"),
  "customer_orders": [
    {
      "name": "Brush",
      "order_date": ISODate("2015-01-01T00:12:01Z"),
      "order_id": NumberLong("2"),
      "product_id": NumberLong("234"),
      "price": 12
    },
    {
      "order_date": ISODate("2015-12-01T00:00:00Z"),
      "order_id": NumberLong("3"),
      "product_id": NumberLong("245")
    },
    {
      "order_date": ISODate("2015-12-21T00:00:00Z"),
      "order_id": NumberLong("4"),
      "product_id": NumberLong("267")
    },
    {
      "order_id": NumberLong("5"),
      "order_date": ISODate("2015-12-29T00:00:00Z"),
      "product_id": NumberLong("289")
    },
    {
      "name": "Brush",
      "order_id": NumberLong("9"),
      "order_date": ISODate("2015-02-01T00:12:05Z"),
      "product_id": NumberLong("234"),
      "price": 12
    }
  ]
}

已尝试的查询:

db.customer.update({"customer_orders.product_id" : 234 , "customer_orders.name" : {$exists : false}}, {"$set" : {"customer_orders.$.name" : "Brush", "customer_orders.$.price" : 12} } )

返回0个更新的文档。你知道吗

db.customer.update({"customer_orders.product_id" : 234 , "customer_orders.name" : {$exists : true}}, {"$set" : {"customer_orders.$.name" : "Brush", "customer_orders.$.price" : 12} } )

返回1个已更新的文档,但即使在连续执行同一命令之后,也只更新第一个字段。那么,有解决方法吗?或者我需要在Python客户机中进行更新吗?你知道吗


Tags: name文档idfalsedateaddressexistsorder
1条回答
网友
1楼 · 发布于 2024-09-29 05:29:24

除了读取文档以找出有多少数组元素并按索引(或不同的“id”值)更新它们之外,没有什么比这更重要的了,但是除了先读取对象之外,这其实并不重要。你知道吗

最安全的方法是,不要更改整个文档并将其“保存”回来,而是对每个数组元素执行更新:

id = ObjectId("559a2d9bfffe043444c72889")
doc = coll.find_one({ "_id": id  })

for idx, el in enumerate(doc["customer_orders"]):
    if ( el["product_id"] == 234 ):
        update = { "$set": {} }
        update["$set"]["customer_orders."+str(idx)+".price"] = 12
        update["$set"]["customer_orders."+str(idx)+".name"] = "Brush"
        coll.update({ "_id": id },update)

通过批量操作,您可以提高效率:

id = ObjectId("559a2d9bfffe043444c72889")
doc = coll.find_one({ "_id": id  })
bulk = coll.initialize_ordered_bulk_op()

for idx, el in enumerate(doc["customer_orders"]):
    if ( el["product_id"] == 234 ):
        update = { "$set": {} }
        update["$set"]["customer_orders."+str(idx)+".price"] = 12
        update["$set"]["customer_orders."+str(idx)+".name"] = "Brush"
        bulk.find({ "_id": id }).update(update)

bulk.execute()

它至少一次将所有更新发送到服务器

但一般的过程是,为了发送正确的更新位置,您需要通过其他唯一标识符的索引来标识“精确”元素。你知道吗

尝试类似

{ "customer_orders.price": { "$exists": False } }

或者

{ "customer_orders.product_id": 234 }

将遇到以下问题:

  • 总之,在这两种情况下,它都会匹配多个对象
  • 对于$exists,对于位置$匹配操作是不可接受的,只有精确的值匹配才能生成用于更新的索引。你知道吗

因此,从文档本身读取“精确的”id或位置索引,然后处理更新。你知道吗

相关问题 更多 >