如何在MongoDB查询条件中模拟子查询

时间:2015-07-13 12:58:22

标签: mysql mongodb mongodb-query

假设我有一个产品日志集合,我的产品上所做的所有更改都将记录在此集合中,即:

+------------------------------+
| productId - status - comment |
| 1           0        ....    |
| 2           0        ....    |
| 1           1        ....    |
| 2           1        ....    |
| 1           2        ....    |
| 3           0        ....    |
+------------------------------+

我希望获得状态为1但尚未成为2的所有产品。在SQL中,查询看起来像:

select productId from productLog as PL1 
where 
   status = 1 
   and productId not in (
       select productId from productLog as PL2 where 
           PL1.productId = PL2.productId and PL2.status = 2
   )
group by productId

我正在使用本机PHP MongoDB驱动程序。

2 个答案:

答案 0 :(得分:1)

因为子查询连接中的逻辑只是完全相同的键匹配另一个:

设置

db.status.insert([
    { "productId": 1, "status": 0 },
    { "productId": 2, "status": 0 },
    { "productId": 1, "status": 1 },
    { "productId": 2, "status": 1 },
    { "productId": 1, "status": 2 },
    { "productId": 3, "status": 0 }
])

然后使用.aggregate()

db.status.aggregate([
    { "$match": {
        "status": { "$ne": 2 }
    }},
    { "$group": {
        "_id": "$productId"
    }}
])

或使用map reduce(使用DBRef):

db.status.mapReduce(
    function() {
        if ( this.productId.$oid == 2 ) {
            emit( this.prouctId.$oid, null )
        }
    },
    function(key,values) {
        return null;
    },
    { "out": { "inline": 1 } }
);        

但这里的SQL再次简单如下:

select productId
from productLog
where status <> 2
group by productId

没有多余的连接在完全相同的键值

答案 1 :(得分:0)

上面的此mongo查询不符合相关要求, mongo查询的结果包括带有productId=1的文档, 但是有关SQL的结果却没有。因为在示例数据中:存在1条带有status=2的记录,而该文档的productId为1。

因此,假设如上所述执行db.productLog.insert,则可以使用以下代码获取结果:

//First: subquery for filtering records having status=2: 
var productsWithStatus2 = db.productLog .find({"status":2}).map(function(rec) { return rec.productId; }); 

//Second:final query to get productIds which there not exists having status=2 with same productId :
db.productLog.aggregate([ {"$match":{productId:{$nin:productsWithStatus2}}},{"$group": {"_id": "$productId"}}])  ;

//Alternative for Second final query:
//db.productLog.distinct("productId",{productId:{$nin:productsWithStatus2}}); 

//Alternative for Second final query,get results with product and status detail:
//db.productLog.find({productId:{$nin:productsWithStatus2}});