Pymongo:从数组中删除一个元素

时间:2013-09-27 22:53:27

标签: python mongodb pymongo

我正试图在我的架构中删除iPad的最低价格。我知道如何使用pymongo找到它,但我不知道如何删除它。 这是我的架构:

{
    "_id": "sjobs",
    "items": [
        {
            "type": "iPod",
            "price": 20.00
        },
        {
            "type": "iPad",
            "price": 399.99
        },
        {
            "type": "iPad",
            "price": 199.99
        },
        {
            "type": "iPhone 5",
            "price": 300.45
        }
    ]
}
{
    "_id": "bgates",
    "items": [
        {
            "type": "MacBook",
            "price": 2900.99
        },
        {
            "type": "iPad",
            "price": 399.99
        },          
        {
            "type": "iPhone 4",
            "price": 100.00
        },
        {
            "type": "iPad",
            "price": 99.99
        }
    ]
}

我有一个python循环,找到iPad的最低销售价格:

cursor = db.sales.find({'items.type': 'iPad'}).sort([('items', pymongo.DESCENDING)])
for doc in cursor:
    cntr = 0
    for item in doc['items']:
        if item['type'] == 'iPad' and resetCntr == 0:
            cntr = 1
            sales.update(doc, {'$pull': {'items': {item['type']}}})

这不起作用。我需要做些什么来删除最低的iPad价格项目?

3 个答案:

答案 0 :(得分:2)

您的Python代码没有按照您的想法执行(除非您没有包含很多内容)。您不需要在客户端进行排序和迭代 - 您应该让服务器完成工作。运行这个聚合管道(我给出了shell语法,你当然可以从Python调用它):

> r = db.sales.aggregate( {"$match"  : { "items.type":"iPad"} },
                          {"$unwind" :   "$items"}, 
                          {"$match"  : { "items.type":"iPad"} },
                          {"$group"  : { "_id" : "$_id", 
                                         "lowest" : {"$min":"$items.price"}, 
                                         "count":{$sum:1}
                                       }
                          }, 
                          {"$match"  : {count:{$gt:1}}}
);
{
    "result" : [
        {
            "_id" : "bgates",
            "lowest" : 99.99,
            "count" : 2
        },
        {
            "_id" : "sjobs",
            "lowest" : 199.99,
            "count" : 2
        }
    ],
    "ok" : 1
}

现在您可以遍历“r.results”数组并执行更新:

db.sales.update( { "_id" : r.results[0]._id }, 
                 { "$pull" : { "items" : { "type" : "iPad", "price" : r.result[0].lowest}}} );

请注意,我只包含有多个iPad的记录 - 否则您最终可能会删除阵列中唯一的iPad记录。如果您要删除所有“非最高”价格,那么您需要查找价格最高且$pull所有元素$lt

答案 1 :(得分:1)

免责声明:以下代码未经过测试,因为我没有在本地安装mongo。然而,我确实花了我的时间写它,所以我非常有信心它接近工作

def remove_lowest_price(collection):
    cursor = collection.find({}, {'items': 1})
    for doc in cursor:
        items = doc['items']
        id = doc['_id']
        for item in items:
            lowest_price = 100000 # a huge number
            if item['type'] == 'i_pad' and item['price'] < lowest:
                lowest = item['price']
        # lowest now contains the price of the cheapest ipad
        collection.update(
            {'_id': id},
            {'$pull': {'items': {'price': lowest}}}
        )

当然,如果另一件物品的价格完全相同,那么这里会有问题,但我认为从这里开始很容易改进

答案 2 :(得分:0)

{'$pull': {'items': {item['type']}}}

这看起来不像有效的json,是吗?

在你的例子中,

不应该是“sales.update(...)”是“db.sales.update(...)”吗?

也许最好在更新操作中进行查询:

db.sales.update({_id: doc[_id]}, ...)

而不是整个文档。

最后更新正文可能是

{'$pull': {'items': {type: item['type']}}}