如何使用子查询返回的值列表查询类似于“不在”的mongodb集合

如何使用子查询返回的值列表查询类似于“不在”的mongodb集合,mongodb,Mongodb,我是mongoDB新手,使用版本2.6.4。我一直在写mongo查询,并在这里寻求专家的帮助 我在myCollection中有以下示例文档: { msgID: "1011", journalID: 1, status: "FLAGGED", timeSent: ISODate("2015-10-27T03:44:19.359Z") }, { msgID: "1012", journalID: 1, status: "FLAGGED",

我是mongoDB新手,使用版本2.6.4。我一直在写mongo查询,并在这里寻求专家的帮助

我在myCollection中有以下示例文档:

{   msgID: "1011",
    journalID: 1,   
    status: "FLAGGED",
    timeSent: ISODate("2015-10-27T03:44:19.359Z") },

{   msgID: "1012",
    journalID: 1,   
    status: "FLAGGED",
    timeSent: ISODate("2015-10-28T07:12:03.446Z") },

{   msgID: "1012",
    journalID: 2,   
    status: "INITIATED",
    timeReceived: ISODate("2015-10-28T08:06:21.221Z") },

{   msgID: "1013",
    journalID: 1,   
    status: "FLAGGED",
    timeSent: ISODate("2015-10-28T13:21:13.568Z") },

{   msgID: "1013",
    journalID: 2,   
    status: "INITIATED",
    timeReceived: ISODate("2015-10-28T13:56:06.419Z") },

{   msgID: "1013",
    journalID: 3,   
    status: "CLOSED",
    timeReceived: ISODate("2015-10-28T16:11:38.875Z") },

{   msgID: "1014",
    journalID: 1,   
    status: "FLAGGED",
    timeSent: ISODate("2015-10-29T13:21:13.568Z") },

{   msgID: "1015",
    journalID: 1,   
    status: "FLAGGED",
    timeSent: ISODate("2015-10-28T08:26:57.828Z") },

{   msgID: "1016",
    journalID: 1,   
    status: "FLAGGED",
    timeSent: ISODate("2015-10-28T11:03:09.075Z") },

{   msgID: "1016",
    journalID: 2,   
    status: "CLOSED",
    timeReceived: ISODate("2015-10-28T14:19:19.907Z") }
如何编写mongo查询,以从myCollection获取满足以下条件的文档:

返回所有仅具有标记状态记录的msgID,即。 排除包含已启动或已关闭项的msgID 状态 其中,timeSent<2015年10月29日 预期结果将是:

我知道在SQL中,这可以通过以下查询实现:

SELECT  m1.msgID, m1.status, m1.timeSent
FROM    myCollection m1
WHERE   m1.msgID NOT IN
            ( SELECT m2.msgID FROM myCollection m2 WHERE m2.status IN ('INITIATED', 'CLOSED'))
AND     m1.status = "FLAGGED"
AND     m1.timeSent < "10-29-2015 00:00:00"
任何帮助都将不胜感激。

如前所述,最好更改模式。您不应该为每个状态添加文档,而应该按照msgID对项目进行分组,并将项目添加到数组中。前三个文档如下所示:

{
    msgID: "1011",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-27T03:44:19.359Z")
    }]
},
{
    msgID: "1012",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-28T07:12:03.446Z")
    }, {
        journalID: 2,   
        status: "INITIATED",
        timeReceived: ISODate("2015-10-28T08:06:21.221Z")
    }]
}
db.getCollection('someCollection').find({
    items: {
        $size : 1
    },
    'items.status': 'FLAGGED'
});
这允许您以更好的性能进行更好的查询。您的查询将如下所示:

{
    msgID: "1011",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-27T03:44:19.359Z")
    }]
},
{
    msgID: "1012",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-28T07:12:03.446Z")
    }, {
        journalID: 2,   
        status: "INITIATED",
        timeReceived: ISODate("2015-10-28T08:06:21.221Z")
    }]
}
db.getCollection('someCollection').find({
    items: {
        $size : 1
    },
    'items.status': 'FLAGGED'
});
如前所述,最好更改模式。您不应该为每个状态添加文档,而应该按照msgID对项目进行分组,并将项目添加到数组中。前三个文档如下所示:

{
    msgID: "1011",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-27T03:44:19.359Z")
    }]
},
{
    msgID: "1012",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-28T07:12:03.446Z")
    }, {
        journalID: 2,   
        status: "INITIATED",
        timeReceived: ISODate("2015-10-28T08:06:21.221Z")
    }]
}
db.getCollection('someCollection').find({
    items: {
        $size : 1
    },
    'items.status': 'FLAGGED'
});
这允许您以更好的性能进行更好的查询。您的查询将如下所示:

{
    msgID: "1011",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-27T03:44:19.359Z")
    }]
},
{
    msgID: "1012",
    items: [{
        journalID: 1,   
        status: "FLAGGED",
        timeSent: ISODate("2015-10-28T07:12:03.446Z")
    }, {
        journalID: 2,   
        status: "INITIATED",
        timeReceived: ISODate("2015-10-28T08:06:21.221Z")
    }]
}
db.getCollection('someCollection').find({
    items: {
        $size : 1
    },
    'items.status': 'FLAGGED'
});

您可以使用find轻松完成此操作

查询-指定SQL中可选WHERE子句的选择条件 投影-匹配文档中的所有字段可选

根据你的问题可以解决如下

  db.flagged.find({
        status: 'FLAGGED',
        timeSent: {
            $lt: ISODate('2015-10-29T00:00:00')
        },
        {msgID:1,status:1,timeSent:1}
    });

更多详细信息如下

您可以使用find轻松完成此操作

  db.flagged.find({
        status: 'FLAGGED',
        timeSent: {
            $lt: ISODate('2015-10-29T00:00:00')
        },
        {msgID:1,status:1,timeSent:1}
    });
查询-指定SQL中可选WHERE子句的选择条件 投影-匹配文档中的所有字段可选

根据你的问题可以解决如下

  db.flagged.find({
        status: 'FLAGGED',
        timeSent: {
            $lt: ISODate('2015-10-29T00:00:00')
        },
        {msgID:1,status:1,timeSent:1}
    });

下面的更多详细信息

虽然它不是从性能角度优化的,而且我了解存储和检索此类数据所需的架构更改,但只是为了与大家分享,我可以根据给定的数据结构找出查询:

  db.flagged.find({
        status: 'FLAGGED',
        timeSent: {
            $lt: ISODate('2015-10-29T00:00:00')
        },
        {msgID:1,status:1,timeSent:1}
    });
db.myCollection.aggregate(
    { $group: {
      _id: "$msgID", stateChange: { $push: { status: "$status", timeSent: "$timeSent" }}}
    },
    { $match: {
        "stateChange.status": { $eq: 'FLAGGED', $nin: ['INITIATED','CLOSED'] }, 
        "stateChange.timeSent": { $lt: ISODate("2015-10-29T00:00:00")}}
    },
    { $unwind: "$stateChange" },
    { $project: {
        _id: 0, msgID: "$_id", status: "$stateChange.status", timeSent: "$stateChange.timeSent"}
    }
)

虽然它没有从性能角度进行优化,而且我了解存储和检索此类数据所需的模式更改,但只是为了与所有人共享,我可以根据给定的数据结构找出查询:

db.myCollection.aggregate(
    { $group: {
      _id: "$msgID", stateChange: { $push: { status: "$status", timeSent: "$timeSent" }}}
    },
    { $match: {
        "stateChange.status": { $eq: 'FLAGGED', $nin: ['INITIATED','CLOSED'] }, 
        "stateChange.timeSent": { $lt: ISODate("2015-10-29T00:00:00")}}
    },
    { $unwind: "$stateChange" },
    { $project: {
        _id: 0, msgID: "$_id", status: "$stateChange.status", timeSent: "$stateChange.timeSent"}
    }
)

更重要的是,如果您查看并理解这里给出的SQL查询,那么子查询甚至不是必需的,真正的查询只需要查找标记的状态和范围内的时间。因此,这里的教训是不要试图重现编写糟糕的SQL的操作,而要解决数据选择问题。一个msgID可以有多个状态为“已标记”、“已启动”、“已关闭”的记录。。。。。等等我不想让那些有“INITIATED”或“CLOSED”记录的msgID,因此这个子查询过滤掉这些msgID。子查询基本上是一个连接,MongoDB不以任何方式执行连接。这不是一个很好的设计,因为当前的SQL只会查找并排除与排除值匹配的所有文档/记录。首先标记逻辑前提,因此任何具有多个状态的内容都应该被排除。最好是使用一系列状态更改对其进行建模,而不是在集合中创建单独的对象。那么查询就变得非常简单了。@Blakes Seven同意你的看法,我需要更改模型以在数组级别捕获每个msgID的日志详细信息。谢谢。更重要的是,如果您查看并理解这里给出的SQL查询,子查询甚至不是必需的,真正的查询只需要查找标记的状态和范围内的时间。因此,这里的教训是不要试图重现编写糟糕的SQL的操作,而要解决数据选择问题。一个msgID可以有多个状态为“已标记”、“已启动”、“已关闭”的记录。。。。。等等我不想让那些有“INITIATED”或“CLOSED”记录的msgID,因此这个子查询过滤掉这些msgID。子查询基本上是一个连接,MongoDB不以任何方式执行连接。这不是一个很好的设计,因为当前的SQL只会查找并排除与排除值匹配的所有文档/记录。首先标记逻辑前提,因此任何具有多个状态的内容都应该被排除。最好是使用一系列状态更改对其进行建模,而不是在集合中创建单独的对象。那么查询就变得非常简单了。@Blakes Seven同意你的看法,我需要更改模型以在数组级别捕获每个msgID的日志详细信息。谢谢,我喜欢。NoSQL设计变得简单。@BlakesSeven感谢您的反馈!为了记录在案,我以前的评论都被删除了,因为它没有添加到答案的当前状态中,这是非常好的,这是人们真正应该遵循的示例。@ThomasBormans Perfect!!非常感谢您的指导。我
我将按照这个简单的NoSQL设计进行模式更改。我喜欢它。NoSQL设计变得简单。@BlakesSeven感谢您的反馈!为了记录在案,我以前的评论都被删除了,因为它没有添加到答案的当前状态中,这是非常好的,这是人们真正应该遵循的示例。@ThomasBormans Perfect!!非常感谢您的指导。我将按照这个简单的NoSQL设计进行模式更改。