检索嵌套数组集合的MongoDB查询

4
{
    "_id" : ObjectId("576155a6cd87b68f7e6e42c9"),
    "First_Name" : "ok",
    "Last_Name" : "jaao",
    "Email" : "xyz@gmail.com",
    "Sessions" : [
        {
            "Last_Login" : "Wed, Jun 14, 2016 6:48 PM",
            "Class" : "fb",
            "ID" : "123"
        },
        {
            "Last_Login" : "Wed, Jun 15, 2016 6:48 PM",
            "ID" : "111",
            "Class" : "fb"
        }
    ],
    "Count" : 2
},
{
    "_id" : ObjectId("576155ccf6d8979e7e77df27"),
    "First_Name" : "abc",
    "Last_Name" : "xyz",
    "Email" : "xyz@gmail.com",
    "Sessions" : [
        {
            "Last_Login" : "Wed, Jun 15, 2016 6:49 PM",
            "Class" : "fb",
            "ID" : "123"
        }
    ],
    "Count" : 1
}

这是我的JSON结构。我想要一个MongoDB查询,以检索今天登录过的每个用户,即其Last_Login具有今天的日期。
我希望我的输出为:
{
    "_id" : ObjectId("576155a6cd87b68f7e6e42c9"),
    "First_Name" : "ok",
    "Last_Name" : "jaao",
    "Email" : "xyz@gmail.com",
    "Sessions" : [
        {
            "Last_Login" : "Wed, Jun 15, 2016 6:48 PM",
            "ID" : "111",
            "Class" : "fb"
        }
    ],
    "Count" : 2
},
{
    "_id" : ObjectId("576155ccf6d8979e7e77df27"),
    "First_Name" : "abc",
    "Last_Name" : "xyz",
    "Email" : "xyz@gmail.com",
    "Sessions" : [
        {
            "Last_Login" : "Wed, Jun 15, 2016 6:49 PM",
            "Class" : "fb",
            "ID" : "123"
        }
    ],
    "Count" : 1
}

1
存储这样的日期将需要复杂的查询,可能会无效。考虑更改模式,将“Last_Login”日期存储为“ISODate()”。 - chridam
Last_Login字段包含moment.js库提供的moment().format('llll')格式的数据,我是否仍需要将其更改为ISODate()? - Shravan Kumar Suthaar
是的,在MongoDB中,最好将日期存储为正确的Date()类型,而不是以上述格式存储为字符串。 - chridam
能否请您给我一个将其插入为ISODate()的例子,现在我是这样使用的:Last_Login: moment.format('llll')。 - Shravan Kumar Suthaar
moment()有一个toDate()方法,你可以使用它来返回一个JavaScript日期对象,或者直接创建一个新的JS日期对象实例。所以你可以这样做:Last_Login: moment().toDate() 或者 Last_Login: new Date() - chridam
好的..使用Date()已经完成了,但我没有得到预期的输出。它输出了匹配对象中的所有数据,甚至包括昨天的登录时间,请仔细查看我的期望输出。 - Shravan Kumar Suthaar
1个回答

1

你需要$elemMatchaggregate

db.users.aggregate([
    {
        $unwind: "$Sessions"
    },
    {
        $match: {
            "Sessions.Last_Login": {
                $gte: ISODate("2016-06-16T00:00:00.0Z"),
                $lt: ISODate("2016-06-17T00:00:00.0Z")
            }
        }
    },
    {
        $group: {
            _id: {
                _id: "$_id",
                First_Name: "$First_Name",
                Last_Name: "$Last_Name"
            },
            Sessions: {
                $push: "$Sessions"
            }
        }
    },
    {
        $project: {
            _id: "$_id._id",
            First_Name: "$_id.First_Name",
            Last_Name: "$_id.Last_Name",
            Sessions: "$Sessions"
        }
    }
])

所以查询将执行以下步骤:
  1. $unwind 所有的 Sessions 元素
  2. $match 日期范围内的文档
  3. $group 按照 _idFirst_NameLast_Name 将文档组合在一起
  4. $project 将文档呈现为原始格式
我省略了一些字段,但是你可以在 $group$project 步骤中轻松添加它。当然,您需要更改日期范围。
我担心这个查询在大集合中的性能。也许最好使用我提供的第一个查询并在代码中过滤所需的会话。 编辑: 如 @chridam 所说,仅当您将 Last_Login 更改为 ISODate() 时,此查询才有效,这是推荐的做法。 编辑 2: 更新查询以使用 aggregate 并匹配仅在日期范围内获取 Sessions 的请求。
这是旧版本:
db.users.filter({
    'Sessions': {
        '$elemMatch': {
            'Last_Login': {
                '$gte': ISODate("2016-06-16T00:00:00.0Z"),
                '$lt': ISODate("2016-06-17T00:00:00.0Z")
            }
        }
    }
})

不太确定查询是否有效,因为OP提供的“Last_Login”日期是一个字符串。 - chridam
@chridam 没问题,我没注意到。 - Luiz de Prá
ISODate()未定义...其他替代方案? - Shravan Kumar Suthaar
你想要返回仅最后一次登录会话吗? - Luiz de Prá
不,仅返回与今天会话对应的条目。 - Shravan Kumar Suthaar
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接