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

【讨论】:

以上是关于返回一个在 mongoDB 中有一个数组的字段,并返回该数组中的第一个和最后一个值的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB通过***属性和嵌套数组键查找文档,并返回匹配文档的一部分

用于在字段之间搜索一个字母数字邮政编码的 Mongodb 查询

关于php查询mongodb限制返回字段的问题

mongodb aggregate

基于键合并两个数组并使用 mongodb 聚合添加新字段

如何填充外部字段 ID 的 MongoDB 数组?