返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值
Posted
技术标签:
【中文标题】返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值【英文标题】:Return a field that has an array in mongoDB, and return the first and last value in that array 【发布时间】:2014-09-16 09:15:38 【问题描述】:场景:考虑存在于 MongoDB 中名为 twitCount 的集合中的文档。
"_id" : ObjectId("53d1340478441a1c0d25c40c"),
"items" : [
"date" : ISODate("2014-07-22T22:18:05.000Z"),
"value" : 4,
"_id" : ObjectId("53d134048b3956000063aa72")
,
"date" : ISODate("2014-07-21T22:09:20.000Z"),
"value" : 10,
"_id" : ObjectId("53d134048b3956000063aa71")
...
],
"ticker" : "OM:A1M"
我只想获取“items”中的第一个和最后一个日期。我尝试了很多不同的“查询”。但我无法做到正确。 “代码”是独一无二的
以下查询是唯一返回某些内容的查询,但它返回所有内容(这是预期的)。
twitCount.aggregate([ $match : ticker: theTicker ], function(err, result)
if (err)
console.log(err);
return;
console.log(result)
)
所以,最后我希望查询返回如下内容 [2013-02-01, 2014-07-24]; 我真的需要这方面的帮助,manual/core/aggregation 上的所有链接都是紫色的,我不知道从哪里获得更多信息。
【问题讨论】:
我很懒,只会投影整个数组,然后对结果执行移位和弹出 ^.^ Mongodb 有一个$pop operator,其中一个例子是删除数组的第一个元素,如果我可以让它工作,我会发布一个实际的答案,但现在玩这个。跨度> 还有一个使用 slice 解决类似问题的答案:***.com/questions/7223273/… @JakeSellers 您的第一个陈述可能是正确的,但其他两个不适用。$pop
将修改集合中存储的文档,$slice
不能在一个查询中同时返回“first”和“last”。因此,选择实际上归结为一个文档的 javascript 或解释多个文档的聚合过程。
同意,$pop 在阅读文档后立即退出,我花了一些时间玩 $slice 和不同的组合,但无法使其工作。
【参考方案1】:
很难判断您的意图是使用单个文档还是使用符合您条件的多个文档。正如建议的那样,单个文档实际上只涉及对单个结果使用 JavaScript 原生的 shift
和 pop
方法来获取数组的第一个和最后一个元素。您可能还需要在这里使用数组排序
twitCount.findOne( "ticker": "OM:A1M" ,function(err,doc)
doc.items = doc.items.sort(function(a,b)
return ( a.date.valueOf() > b.date.valueOf() ) ? 1
: ( a.date.valueOf() < b.date.valueOf() ) ? -1 : 0;
);
doc.items = [doc.items.shift(),doc.items.pop()];
console.log( doc );
)
其他建议并不真正适用,因为像 $pop
这样的运算符会在更新中永久修改数组。并且可以在查询中使用的 $slice
运算符实际上只有在数组内容已经排序时才对您有用,此外,您将进行两个查询以返回第一个和最后一个,这不是您想要的。
但是,如果您真的希望在多个文档上执行此操作,那么聚合框架就是答案。使用数组时要了解的关键领域是您必须首先在数组上使用$unwind
管道阶段。这将“反规范化”为为每个数组元素有效生成文档副本的形式:
twitCount.aggregate([
// Match your "documents" first
"$match": "ticker": "OM:A1M" ,
// Unwind the array
"$unwind": "$items" ,
// Sort the values
"$sort": "items.date": 1 ,
// Group with $first and $last items
"$group":
"_id": "$ticker",
"first": "$first": "$items" ,
"last": "$last": "$items"
],function(err,result)
如果你真的想把“项目”作为一个数组返回,那么你可以做一些不同的事情:
twitCount.aggregate([
// Match your "documents" first
"$match": "ticker": "OM:A1M" ,
// Unwind the array
"$unwind": "$items" ,
// Sort the values
"$sort": "items.date": 1 ,
// Group with $first and $last items
"$group":
"_id": "$ticker",
"first": "$first": "$items" ,
"last": "$last": "$items" ,
"type": "$first": "$const": [true,false]
,
// Unwind the "type"
"$unwind": "$type" ,
// Conditionally push to the array
"$group":
"_id": "$_id",
"items":
"$push":
"$cond": [
"$type",
"$first",
"$last"
]
],function(err,result)
或者,如果您的 $match
语句只是用于选择并且您想要每个文档“_id”中的“第一个”和“最后一个”,那么您只需将初始 $group
中的键更改为“$_id”而不是比“$ticker”字段值:
twitCount.aggregate([
// Match your "documents" first
"$match": "ticker": "OM:A1M" ,
// Unwind the array
"$unwind": "$items" ,
// Sort the values
"$sort": "items.date": 1 ,
// Group with $first and $last items
"$group":
"_id": "$_id",
"ticker": "$first": "$ticker" ,
"first": "$first": "$items" ,
"last": "$last": "$items" ,
"type": "$first": "$const": [true,false]
,
// Unwind the "type"
"$unwind": "$type" ,
// Conditionally push to the array
"$group":
"_id": "$_id",
"ticker": "$first": "$ticker" ,
"items":
"$push":
"$cond": [
"$type",
"$first",
"$last"
]
],function(err,result)
在最后一种情况下,根据您提供的数据,您会得到类似的结果:
"_id" : ObjectId("53d1340478441a1c0d25c40c"),
"ticker" : "OM:A1M",
"items" : [
"date" : ISODate("2014-07-21T22:09:20Z"),
"value" : 10,
"_id" : ObjectId("53d134048b3956000063aa71")
,
"date" : ISODate("2014-07-22T22:18:05Z"),
"value" : 4,
"_id" : ObjectId("53d134048b3956000063aa72")
]
您可以在文档中找到Full List of Aggregation Operators。值得了解这些功能是如何发挥作用的,因为聚合框架可能是一个非常有用的工具。
【讨论】:
以上是关于返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB通过***属性和嵌套数组键查找文档,并返回匹配文档的一部分