用mongodb进行管道操作

时间:2014-04-25 19:52:04

标签: mongodb aggregation-framework

我是mongo的新手,我正在寻找一种简单的方法来使用一个命令进行排序和删除:

{u'house_id': 199, u'_id': ObjectId('50906d7fa3c412bb040eb896'), u'type': u'house', u'rate': 58.09608083191365}
{u'house_id': 199, u'_id': ObjectId('50906d7fa3c412bb040eb895'), u'type': u'house', u'rate': 49.34223066136407}
{u'house_id': 198, u'_id': ObjectId('50906d7fa3c412bb040eb891'), u'type': u'house', u'rate': 76.18366499496366}
{u'house_id': 198, u'_id': ObjectId('50906d7fa3c412bb040eb892'), u'type': u'house', u'rate': 17.46279901047208}

如何使用相同的house_id删除率最低的文档?

2 个答案:

答案 0 :(得分:1)

不幸的是,remove和update命令还不允许在其中使用通用游标方法(https://jira.mongodb.org/browse/SERVER-1599),因此目前最好的方法是执行查找然后删除:

var houses = db.collection.find({house_id: 199}).sort({rate: 1});
houses.forEach(function(doc){
    db.collection.remove({_id: house._id});
    return;
})

这是目前最好的方式。

答案 1 :(得分:1)

虽然这里的基本答案是你需要循环结果,你可能会通过获得所有"最小值"来做得更好。一击中的文件。 aggregation framework对此非常有用,因为您可以将$first运算符与$sort结合使用:

var result  = db.collection.aggregate([
    { "$sort": { 
        "house_id": 1,
        "rate": 1
    }},
    { "$group": {
        "_id": "$house_id",
        "docId": { "$first": "$_id" },
        "count": { "$sum": 1 }
    }},
    { "$match": {
        "count": { "$gt": 1 }
    }}
])

这会产生包含整个集合中所有费率最低的文档的结果,当然会丢弃任何仅为您的" house_id"因为你不想删除它。

然后,如果你真的可以逃脱它,你可以将所有这些结果应用到$in运算符,并使用一点映射来提取您需要的_id值:

var ids = [];
result.result.forEach(function(doc) {
    ids.push( doc.docId );
});

db.collection.remove({ "_id": { "$in": ids } })

同时注意到.remove()的默认形式将对所有匹配的文档起作用,除非指定了一个可选的运算符以仅删除一个。但这可以用于此目的。

从MongoDB 2.6,您可以访问"光标"返回了汇总结果,因此您可以选择在大型结果集上进行改进:

var ids = [];
var cursor = db.collection.aggregate([
    { "$sort": { 
        "house_id": 1,
        "rate": 1
    }},
    { "$group": {
        "_id": "$house_id",
        "docId": { "$first": "$_id" },
        "count": { "$sum": 1 }
    }},
    { "$match": {
        "count": { "$gt": 1 }
    }}
]);

cursor.forEach(function(doc) {
    ids.push( doc.docId );

    if ( ids.length % 500 == 0 ) {
        db.collection.remove({ "_id": { "$in": ids } });
        ids = [];
    }

});

if ( ids.length > 0 )
    db.collection.remove({ "_id": { "$in": ids } });

或者对于具有该基本结构的任何语言的一般实现。

所以你并不完全是#34;管道"或者"查询"因为不支持这样的操作。但是$in运算符是在这里高效组合的方式,以及聚合为您提供一种有效的方法来找到您的最低"结果

它通常应该比循环每个可能的更有效" house_id"使用.find()以及.sort().limit(1)修饰符的值可能已经实现或在此处另有建议。

同样反对另有建议,你不会导致删除"所有"如果您刚刚将.limit(1)添加到您的查找中(如未显示),您不知道是否只有一个结果,那么您的文档就是如此。而且您可能不想删除您唯一的文档。