我有一个mongodb集合,看起来像这样:
db.scores.insert({"name": "Bob", value: 96.3, timeStamp:'2010-9-27 9:32:00'}) db.scores.insert({"name": "John", value: 98.3, timeStamp:'2010-9-27 9:28:00'}) db.scores.insert({"name": "Bob", value: 99.3, timeStamp:'2010-9-27 9:29:00'}) db.scores.insert({"name": "John", value: 97.3, timeStamp:'2010-9-27 9:31:00'})
我怎么能查询这个给我一个名字,最近的值:
{name: "John", value: 97.3} {name: "Bob", value: 96.3}
Niels van de.. 5
您正在尝试进行数据聚合,因此您必须编写map-reduce查询.
map函数基本上是GROUP BY
SQL 的子句.在你的情况下,我们将对名称进行分组,因此我们将使用该名称作为key
.在value
将包含我们需要的其他数据,在这种情况下,值和时间戳.
map = function () { emit(this.name, { timeStamp: this.timeStamp, value: this.value }); }
map函数将为每个键生成一个值数组.因此,名为"Bob"的所有文档都映射到密钥"Bob".对于您的示例数据,结果可能如下所示:
{ _id: "Bob", values: [ { timeStamp: "2010-9-27 9:32:00", value: 96.3 }, { timeStamp: "2010-9-27 9:29:00", value: 99.3 } ]}, { _id: "John", values: [ { timeStamp: "2010-9-27 9:28:00", value: 98.3 }, { timeStamp: "2010-9-27 9:31:00", value: 97.3 } ]},
reduce函数负责将每个键的值数组减少为单个值.在您的情况下,我们只对时间戳最高的数据感兴趣:
reduce = function (key, values) { var maxData = { timeStamp: new Date(0) }; values.forEach(function (data) { if (data.timeStamp > maxData.timeStamp) { maxData = data; } }); return maxData; }
请注意,reduce函数的返回值与其接受的值具有相同的格式非常重要.这是因为对于单个密钥可以多次调用reduce函数,每次只接受总值的一部分.
运行reduce函数将导致以下结果:
{ _id: "Bob", value: { timeStamp: "2010-9-27 9:32:00", value: 96.3 } }, { _id: "John", value: { timeStamp: "2010-9-27 9:31:00", value: 97.3 } }
终结函数可用于仅提取我们需要的数据,即值.
finalize = function (key, value) { return value.value; }
这将导致:
{ "_id" : "Bob", "value" : 96.3 }, { "_id" : "John", "value" : 97.3 }
您可以使用以下函数运行map-reduce:
res = db.scores.mapReduce(map, reduce, { finalize: finalize });
该集合db[res.result]
将包含查询的结果.
reduce函数将时间戳比较为Date对象.从示例代码判断,您已将时间戳存储为字符串,而不是Date对象或整数时间戳.因此,在您能够比较日期之前,您必须将这些字符串转换为Date对象.
您正在尝试进行数据聚合,因此您必须编写map-reduce查询.
map函数基本上是GROUP BY
SQL 的子句.在你的情况下,我们将对名称进行分组,因此我们将使用该名称作为key
.在value
将包含我们需要的其他数据,在这种情况下,值和时间戳.
map = function () { emit(this.name, { timeStamp: this.timeStamp, value: this.value }); }
map函数将为每个键生成一个值数组.因此,名为"Bob"的所有文档都映射到密钥"Bob".对于您的示例数据,结果可能如下所示:
{ _id: "Bob", values: [ { timeStamp: "2010-9-27 9:32:00", value: 96.3 }, { timeStamp: "2010-9-27 9:29:00", value: 99.3 } ]}, { _id: "John", values: [ { timeStamp: "2010-9-27 9:28:00", value: 98.3 }, { timeStamp: "2010-9-27 9:31:00", value: 97.3 } ]},
reduce函数负责将每个键的值数组减少为单个值.在您的情况下,我们只对时间戳最高的数据感兴趣:
reduce = function (key, values) { var maxData = { timeStamp: new Date(0) }; values.forEach(function (data) { if (data.timeStamp > maxData.timeStamp) { maxData = data; } }); return maxData; }
请注意,reduce函数的返回值与其接受的值具有相同的格式非常重要.这是因为对于单个密钥可以多次调用reduce函数,每次只接受总值的一部分.
运行reduce函数将导致以下结果:
{ _id: "Bob", value: { timeStamp: "2010-9-27 9:32:00", value: 96.3 } }, { _id: "John", value: { timeStamp: "2010-9-27 9:31:00", value: 97.3 } }
终结函数可用于仅提取我们需要的数据,即值.
finalize = function (key, value) { return value.value; }
这将导致:
{ "_id" : "Bob", "value" : 96.3 }, { "_id" : "John", "value" : 97.3 }
您可以使用以下函数运行map-reduce:
res = db.scores.mapReduce(map, reduce, { finalize: finalize });
该集合db[res.result]
将包含查询的结果.
reduce函数将时间戳比较为Date对象.从示例代码判断,您已将时间戳存储为字符串,而不是Date对象或整数时间戳.因此,在您能够比较日期之前,您必须将这些字符串转换为Date对象.