【问题标题】:Return a field that has an array in mongoDB, and return the first and last value in that array返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值
【发布时间】: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 解决类似问题的答案:stackoverflow.com/questions/7223273/…
  • @JakeSellers 您的第一个陈述可能是正确的,但其他两个不适用。 $pop 将修改集合中存储的文档,$slice 不能在一个查询中同时返回“first”和“last”。因此,选择实际上归结为一个文档的 JavaScript 或解释多个文档的聚合过程。
  • 同意,$pop 在阅读文档后立即退出,我花了一些时间玩 $slice 和不同的组合,但无法使其工作。

标签: json node.js mongodb mongoose aggregation-framework


【解决方案1】:

很难判断您的意图是使用单个文档还是使用符合您条件的多个文档。正如建议的那样,单个文档实际上只涉及对单个结果使用 JavaScript 原生的 shiftpop 方法来获取数组的第一个和最后一个元素。您可能还需要在这里使用数组排序

 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。值得了解这些功能是如何发挥作用的,因为聚合框架可能是一个非常有用的工具。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    • 2022-07-20
    • 2022-06-22
    • 2017-01-10
    • 1970-01-01
    • 2014-11-27
    相关资源
    最近更新 更多