嗯,这是我的收藏品
{
"company" : "500010"
"eqtcorp" : {
"306113" : {
"DATE" : "2014-05-05 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "16:43"
},
"306118" : {
"DATE" : "2014-05-08 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "18:43"
},
"306114" : {
"DATE" : "2014-06-02 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
}
"306116" : {
"DATE" : "2014-03-02 12:30:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
}
"306115" : {
"DATE" : "2014-08-02 04:45:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
}
"306117" : {
"DATE" : "2014-07-02 10:16:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
}
.
.
.
.
.
}
}
如果我查询
db.collection_name.find({"company": "500010"})
我会得到整体。由于“eqtcorp”下有很多子文档,我只需要3个带有最新日期的子文档。只需在“eqtcorp”下的每个子文档中的“DATE”字段的基础上进行反向排序,然后取第3个。这是一个挑战,因为我是Mongodb和mapreduce的新手。
我期待输出的是
{
"company" : "500010"
"eqtcorp" : {
"306113" : {
"DATE" : "2014-05-05 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "16:43"
},
"306118" : {
"DATE" : "2014-05-08 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "18:43"
},
"306116" : {
"DATE" : "2014-03-02 12:30:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
}
}
}
任何拍摄?
答案 0 :(得分:2)
在这里有几件事并没有真正帮助你,这实际上使一个简单的操作变得复杂。
您的日期实际上是您应该更改为正确的BSON日期类型的字符串。它会在以后你可能想要的地方帮助你,所以你应该改变它们。幸运的是,它们至少是按照" YYYY-MM-DD"的顺序排列的。所以他们会对它们进行分类,但是不要期望它们有很多其他用途。
您还应该使用数组而不是按键嵌套子文档。这些实际上很难查询,因为您需要指定元素的确切路径。因此,您几乎总是局限于JavaScript处理,这比替代方案慢得多。我稍后会介绍,但继续前进:
你可以用mapReduce来解决这个问题,如下所示:
db.collection.mapReduce(
function () {
for ( var k in this.eqtcorp ) {
this.eqtcorp[k].key = k;
emit( 1, this.eqtcorp[k] );
}
},
function (key,values) {
var reduced = {};
values.sort(function(a,b) {
return (( a.DATE > b.DATE ) ? -1 : (( a.DATE < b.DATE ) ? 1 : 0));
}).slice(-3).forEach(function(doc) {
reduced[doc.key] = doc;
});
return reduced;
},
{
"query": { "company": "50010" },
"finalize": function(key,vaue) {
for (var k in value) {
delete value[k].key;
}
return value;
},
"out": { "inline": 1 },
})
)
在映射器中,我目前使用发出的密钥1
。这样做的原因是该声明适用于&#34;聚合&#34;跨多个文档的所有结果。但是,如果你真的只想按照你的&#34;公司&#34;然后您可以将其作为键发出,如:
emit( this.company, this.eqtcorp[k] );
基本上,映射器将每个文档分开,只输出&#34; eqtcorp&#34;的每个子键。作为它自己的文件。然后将它们传递给减速器。
可以多次调用的reducer采用&#34;值的输入数组&#34;对于相同的&#34;关键&#34;并首先使用该数组上的sort
处理它们。一旦排序(按升序排列),然后slice
离开数组的最后三个项目,并将每个项目添加到缩小的结果中。
正如我所说的,可以多次调用reducer,因此每次传递都不一定能得到整个&#34;每个分组键的值列表。这是&#34;减少&#34;的重要组成部分。逐步地,它逐步地增加&#34;获取每个输入集并返回,最终运行已减少的结果组合,直到只有一个&#34;键&#34;只包含您想要的三个结果的值。
然后只有最终化功能,它清理了一些便利的内务管理,以简化原始子文档密钥对结果的处理。其他的东西只是选择查询和输出的选择,根据您的需要可能是另一个集合。或者您当然可以省略选择查询来处理所有文档。
如前所述,文档结构没有帮助,并且更适合于数组。所以你应该有这样一个文件:
{
"company" : "500010",
"eqtcorp" : [
{
"key": "306113"
"DATE" : "2014-05-05 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "16:43"
},
{
"key": "306118",
"DATE" : "2014-05-08 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "18:43"
},
{
"key": "306114",
"DATE" : "2014-06-02 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
},
{
"key:"306116",
"DATE" : "2014-03-02 12:30:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
},
{
"key": "306115",
"DATE" : "2014-08-02 04:45:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
},
{
"key": "306117",
"DATE" : "2014-07-02 10:16:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "20:43"
}
]
}
虽然现在只保留日期格式,但这可以使事情变得更加清晰,因为您可以简化处理,并且如果您打算说&#34;找到前三个值,那么确实使用像聚合框架这样的事情来加快处理速度。 34;整个系列。这很简单:
db.collection.aggregate([
// Unwind the array
{ "$unwind": "$eqtcorp" },
// Sort the results by the dates
{ "$sort": "eqtcorp.DATE" -1 },
// Limit the top three results
{ "$limit": 3 },
// Optionally group back as an array
{ "$group": {
"_id": null,
"eqtcorp": { "$push": "$eqtcorp" }
}}
])
这将是整个集合,获得每个公司价值前三名并非不可能,但更多涉及因为没有相应的切片
db.collection.aggregate([
// Unwind the array
{ "$unwind": "$eqtcorp" },
// Sort the results by company and date
{ "$sort": "company": 1, "eqtcorp.DATE" -1 },
// Group back keeping the top value
{ "$group": {
"_id": "$company",
"all": { "$push": "$eqtcorp" },
"one": { "$first": "$eqtcorp" }
}},
// Unwind again
{ "$unwind": "$all" },
// match the "seen" value
{ "$project": {
"all": 1,
"one": 1,
"seen": {
"$eq": [ "$all", "$one" ]
}
}},
// Filter out "seen"
{ "$match": { "seen": false } },
// Group back keeping the new top
{ "$group": {
"_id": "$_id",
"all": { "$push": "$all },
"one": { "$first": "$one" },
"two": { "$first": "$all }
}},
// Unwind again
{ "$unwind": "$all" },
// Match the seen value
{ "$project": {
"all": 1,
"one": 1,
"two": 1,
"seen": {
"$eq": [ "$all", "$two" ]
}
}},
// Filter the seen value
{ "$match": { "seen": false } },
// Group back again
{ "$group": {
"_id": "$_id",
"one": { "$first": "$one" },
"two": { "$first": "$two },
"three": { "$first": "$three" }
}}
])
或者在mapper上修改map reduce,因为我们实际上只是人工生成数组:
function () {
this.eqtcorp.forEach(doc) {
emit( this.company, doc );
});
}
在组合键
时拆分它仍然有意义当然,如果文档之间没有实际的聚合,你的基本意图就是在每个文档中获取数组的最后三个值,那么明确的方法是&#34; sort&#34;它们随着文档的更新和项目被添加到数组中。因此,您添加新项目的方法将变为:
db.collection.update(
{ _id: document_id },
{
"$push": {
"eqtcorp": {
"$each": [ { new document }, { optionally more} ],
"$sort": { "DATE": 1 }
}
}
}
);
在MongoDB 2.6之前,还需要一个 $slice
修饰符,它基本上会对数组中的项目数施加上限,但不再需要这样。对于早期版本,您可能必须为此提供上限值,例如500
或大于预期结果的其他数字,除非您真的想要修剪&#34;修剪&#34;结果在哪种情况下设定了你的限制。
这里的一点是,如果没有任何聚合,那么当你只想从文档中获取该数组的最后三个值时,你只需要使用投影和那里可用的$slice
运算符:
db.collection.find({},{ "eqtcorp": { "$slice": -3 } })
由于文档中的数组项已经排序,您只需获取最后三个值,即完成。
实际上,虽然您可以使用mapReduce处理现有文档,但除非您真的想要聚合结果,否则这是一个慢得多的过程。将数据更改为数组并维护排序顺序将立即为您提供所需的结果,并且查询速度非常快。
即使你的意图是聚合,那么使用数组时可用的选项要宽得多,而且通常更容易做更复杂的事情。
答案 1 :(得分:1)
如果子文档&#34; eqtcorp&#34;存储为如下所述的数组
{
"name" : "306113", // assigned it to a node to create an array
"DATE" : "2014-05-05 16:43:00.000",
"subsection_name" : "CORPORATE NEWS",
"time" : "16:43"
}
更新单个文档
db.collection_name.update(
{ company : "500010"},
{ $push : {
eqtcorp : {
$each: [ ],
$sort : { "DATE" : -1},
$slice : 3
}
}
})
更新所有文件
db.collection_name.update(
{}, // query all documents
{
$push : {
eqtcorp : {
$each: [ ],
$sort : { "DATE" : -1},
$slice : 3
}
}
},
false,
true // update multiple documents
)
答案 2 :(得分:0)
最简单的查询将根据日期对子文档数组进行排序,并使用“切片”运算符通过投影获取所需的数据
db.collection_name.find({"company": "500010"},{ "eqtcorp": { "$slice": -3 } }).sort({"eqtcorp.DATE":-1})