以下是一些插入语句
db.users.insert({ courseId: 1, stDt: new Date(2014, 01, 01), endDt: new Date(2014, 01, 20), active: false });
db.users.insert({ courseId: 1, stDt: new Date(2014, 01, 25), endDt: new Date(2014, 02, 10), active: false });
db.users.insert({ courseId: 1, stDt: new Date(2014, 02, 25), endDt: new Date(2014, 03, 10), active: true });
db.users.insert({ courseId: 1, stDt: new Date(2014, 02, 28), endDt: new Date(2014, 06, 10), active: true });
db.users.insert({ courseId: 1, stDt: new Date(2014, 02, 25), endDt: new Date(2014, 02, 30), active: false });
db.users.insert({ courseId: 1, stDt: new Date(2014, 05, 25), endDt: new Date(2014, 10, 30), active: false });
db.users.insert({ courseId: 1, stDt: new Date(2013, 10, 01), endDt: new Date(2014, 08, 10), active: true });
db.users.insert({ courseId: 1, stDt: new Date(2014, 09, 01), endDt: new Date(2014, 11, 30), active: false });
案例1:我们可以从上面插入的值创建以下结果集吗?在这里,所有将"活动"字段设置为 true 和 false 的结果都按"endDt"字段排序,该字段通过单个查询单独检索。
{ "result" : {
true : [
{ endDt: new Date(2014, 03, 10), active: true },
{ endDt: new Date(2014, 06, 10), active: true },
{ endDt: new Date(2014, 08, 10), active: true },
],
false: [
{ endDt: new Date(2014, 01, 20), active: false },
{ endDt: new Date(2014, 02, 10), active: false },
{ endDt: new Date(2014, 02, 30), active: false },
{ endDt: new Date(2014, 10, 30), active: false },
{ endDt: new Date(2014, 11, 30), active: false }
]
}
}
可以通过单个查询来完成吗?
案例2:我们可以做以下结果集吗?
{ "result" : [
{ endDt: new Date(2014, 01, 20), active: false },
{ endDt: new Date(2014, 02, 10), active: false },
{ endDt: new Date(2014, 02, 30), active: false },
[
{ endDt: new Date(2014, 03, 10), active: true },
{ endDt: new Date(2014, 06, 10), active: true },
{ endDt: new Date(2014, 08, 10), active: true }
],
{ endDt: new Date(2014, 10, 30), active: false },
{ endDt: new Date(2014, 11, 30), active: false }
]
}
这里按字段排序endDt
但active
字段 true 的最后endDt
条记录将包含所有先前"活动"字段 true 记录的数组。
我认为,第二种情况是不可能的。
第一个很简单,你做这样的事情:
db.users.aggregate({$sort:{endDt:1}}, {$group:{_id:"$active", dates:{$push:"$endDt"}}})
{
"_id" : true,
"dates" : [
ISODate("2014-04-10T07:00:00Z"),
ISODate("2014-07-10T07:00:00Z"),
ISODate("2014-09-10T07:00:00Z")
]
},
{
"_id" : false,
"dates" : [
ISODate("2014-02-20T08:00:00Z"),
ISODate("2014-03-10T07:00:00Z"),
ISODate("2014-03-30T07:00:00Z"),
ISODate("2014-11-30T08:00:00Z"),
ISODate("2014-12-30T08:00:00Z")
]
}
第二个可能是可行的,但您需要更精确地定义您想要返回的内容。
你可以这样使用组命令...
db.users.aggregate({'$group' : {'_id' : '$active','endDt' : {'$addToSet' : '$endDt'}}})
{
"result" : [
{
"_id" : true,
"endDt" : [
ISODate("2014-09-09T21:00:00Z"),
ISODate("2014-07-09T21:00:00Z"),
ISODate("2014-04-09T21:00:00Z")
]
},
{
"_id" : false,
"endDt" : [
ISODate("2014-12-29T21:00:00Z"),
ISODate("2014-11-29T21:00:00Z"),
ISODate("2014-03-29T21:00:00Z"),
ISODate("2014-03-09T21:00:00Z"),
ISODate("2014-02-19T21:00:00Z")
]
}
],
"ok" : 1
}
您可以在 MONGO 文档中阅读更多内容
案例 1 可以返回确切的结果集。但案例 2 不是有效的文件。
实际上,答案是我的朋友道格在他的博客中给我的。我只是将其复制到SO。
这是对案例 1 的查询,它由注释解释。
db.users.aggregate([
// Project only what we need.
{
"$project": {
"endDt": 1,
"active": 1,
"_id": 0
}
},
// Group to true and false buckets. This will give us arrays with null.
// We'll remove them in a bit.
{
"$group": {
"_id": "$active",
"true": {
"$addToSet": {
"$cond": [
{"$eq": ["$active", true]},
"$endDt",
null
]
}
},
"false": {
"$addToSet": {
"$cond": [
{"$eq": ["$active", false]},
"$endDt",
null
]
}
}
}
},
// We need to unwind our arrays so we can build them back up without the
// "null" array.
{"$unwind": "$true"},
{"$unwind": "$false"},
// Project out the values. This will give both a true and false key for
// each item. This builds our arrays up with the proper endDt and
// active values.
{
"$project": {
"true": {"endDt": "$true", "active": "$_id"},
"false": {"endDt": "$false", "active": "$_id"}
}
},
// Project out a single value to clean up the "issue" a couple steps above.
{
"$project": {
"value": {
"$cond": [
{"$eq": ["$_id", true]},
"$true",
"$false"
]
}
}
},
// Group things up again to rebuild our arrays.
// This adds a single "null" entry that will need to be cleaned up.
{
"$group": {
"_id": null,
"true": {
"$addToSet": {
"$cond": [
{"$eq": ["$_id", true]},
"$value",
null
]
}
},
"false": {
"$addToSet": {
"$cond": [
{"$eq": ["$_id", false]},
"$value",
null
]
}
}
}
},
// Unwind our arrays again so we can clean up one more time.
{"$unwind": "$true"},
{"$unwind": "$false"},
// Match only documents where true and false are not null.
{
"$match": {
"true": {"$ne": null},
"false": {"$ne": null}
}
},
// Sort our items so we can add the to the array in the correct order.
// I'm not sure why it has to be descending order, but it works.
{
"$sort": {
"true.endDt": -1,
"false.endDt": -1
}
},
// Group again to build our array.
{
"$group": {
"_id": null,
"true": {"$addToSet": "$true"},
"false": {"$addToSet": "$false"}
}
},
// Once again project out just the fields we need
{
"$project": {
"true": 1,
"false": 1,
"_id": 0
}
}
])
以下是MongoDB 2.2.x - 2.4.x中返回的结果:
{
"result" : [
{
"true" : [
{
"endDt" : ISODate("2014-04-10T06:00:00Z"),
"active" : true
},
{
"endDt" : ISODate("2014-07-10T06:00:00Z"),
"active" : true
},
{
"endDt" : ISODate("2014-09-10T06:00:00Z"),
"active" : true
}
],
"false" : [
{
"endDt" : ISODate("2014-02-20T07:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-03-10T06:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-03-30T06:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-11-30T07:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-12-30T07:00:00Z"),
"active" : false
}
]
}
],
"ok" : 1
}
在即将发布的 2.6.0 版本中,结果如下所示:
{
"true" : [
{
"endDt" : ISODate("2014-04-10T06:00:00Z"),
"active" : true
},
{
"endDt" : ISODate("2014-07-10T06:00:00Z"),
"active" : true
},
{
"endDt" : ISODate("2014-09-10T06:00:00Z"),
"active" : true
}
],
"false" : [
{
"endDt" : ISODate("2014-02-20T07:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-03-10T06:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-03-30T06:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-11-30T07:00:00Z"),
"active" : false
},
{
"endDt" : ISODate("2014-12-30T07:00:00Z"),
"active" : false
}
]
}