2017-07-25 64 views
0

我有一个文档的集合结构如下图所示:使用聚合框架来比较数组元素重叠

{ 
    carrier: "abc", 
    flightNumber: 123, 
    dates: [ 
     ISODate("2015-01-01T00:00:00Z"), 
     ISODate("2015-01-02T00:00:00Z"), 
     ISODate("2015-01-03T00:00:00Z") 
    ] 
} 

我想搜索的集合,看看是否有与相同carrier和​​任何文档也有在dates阵列的日期在一圈。例如:

{ 
    carrier: "abc", 
    flightNumber: 123, 
    dates: [ 
     ISODate("2015-01-01T00:00:00Z"), 
     ISODate("2015-01-02T00:00:00Z"), 
     ISODate("2015-01-03T00:00:00Z") 
    ] 
}, 
{ 
    carrier: "abc", 
    flightNumber: 123, 
    dates: [ 
     ISODate("2015-01-03T00:00:00Z"), 
     ISODate("2015-01-04T00:00:00Z"), 
     ISODate("2015-01-05T00:00:00Z") 
    ] 
} 

如果上面记录存在的集合中,我想回报他们,因为他们都有carrierabc,​​:123和他们也有dates阵列中的日期ISODate("2015-01-03T00:00:00Z")。如果此日期不在第二份文件中,则不应退回。

通常我会用分组和像下面计数做到这一点:

db.flights.aggregate([ 
    { 
    $group: { 
     _id: { carrier: "$carrier", flightNumber: "$flightNumber" }, 
     uniqueIds: { $addToSet: "$_id" }, 
     count: { $sum: 1 } 
    } 
    }, 
    { 
    $match: { 
     count: { $gt: 1 } 
    } 
    } 
]) 

但我不知道我怎么能修改此寻找阵列重叠。任何人都可以建议如何实现?

回答

2

$unwind数组,如果你想看看内容为“分组”,在其中:

db.flights.aggregate([ 
    { "$unwind": "$dates" }, 
    { "$group": { 
    "_id": { "carrier": "$carrier", "flightnumber": "$flightnumber", "date": "$dates" }, 
    "count": { "$sum": 1 }, 
    "_ids": { "$addToSet": "$_id" } 
    }}, 
    { "$match": { "count": { "$gt": 1 } } }, 
    { "$unwind": "$_ids" }, 
    { "$group": { "_id": "$_ids" } } 
]) 

那请问其实告诉你哪些文件里的“重叠”所在,因为“同一日期“以及您关心的其他相同分组键值有一个”计数“,其发生超过一次。指示重叠。

$match之后的任何内容实际上只是用于“展示”,因为如果您只想查看重叠,则没有意见报告多个重叠的相同_id值。事实上,如果你想看到他们在一起,最好离开“分组集”单独。现在

您可以添加一个$lookup到,如果检索实际的文件是对你很重要:

db.flights.aggregate([ 
    { "$unwind": "$dates" }, 
    { "$group": { 
    "_id": { "carrier": "$carrier", "flightnumber": "$flightnumber", "date": "$dates" }, 
    "count": { "$sum": 1 }, 
    "_ids": { "$addToSet": "$_id" } 
    }}, 
    { "$match": { "count": { "$gt": 1 } } }, 
    { "$unwind": "$_ids" }, 
    { "$group": { "_id": "$_ids" } }, 
    }}, 
    { "$lookup": { 
    "from": "flights", 
    "localField": "_id", 
    "foreignField": "_id", 
    "as": "_ids" 
    }}, 
    { "$unwind": "$_ids" }, 
    { "$replaceRoot": { 
    "newRoot": "$_ids" 
    }} 
]) 

而且即使做了$replaceRoot$project使其返回整个文档。或者你甚至可以用$$ROOT完成$addToSet,如果它不是大小问题。

但总体来说,前三个流水线阶段或大部分只是“第一个”。如果你想用“跨文件”的方式处理数组,那么主操作员仍然是$unwind


或者一个更“报告”之类的格式:

db.flights.aggregate([ 
    { "$addFields": { "copy": "$$ROOT" } }, 
    { "$unwind": "$dates" }, 
    { "$group": { 
    "_id": { 
     "carrier": "$carrier", 
     "flightNumber": "$flightNumber", 
     "dates": "$dates" 
    }, 
    "count": { "$sum": 1 }, 
    "_docs": { "$addToSet": "$copy" } 
    }}, 
    { "$match": { "count": { "$gt": 1 } } }, 
    { "$group": { 
    "_id": { 
     "carrier": "$_id.carrier", 
     "flightNumber": "$_id.flightNumber", 
    }, 
    "overlaps": { 
     "$push": { 
     "date": "$_id.dates", 
     "_docs": "$_docs" 
     } 
    } 
    }} 
]) 

这将各组内汇报重叠的日期,告诉你哪些文件载有重叠:

{ 
    "_id" : { 
     "carrier" : "abc", 
     "flightNumber" : 123.0 
    }, 
    "overlaps" : [ 
     { 
      "date" : ISODate("2015-01-03T00:00:00.000Z"), 
      "_docs" : [ 
       { 
        "_id" : ObjectId("5977f9187dcd6a5f6a9b4b97"), 
        "carrier" : "abc", 
        "flightNumber" : 123.0, 
        "dates" : [ 
         ISODate("2015-01-03T00:00:00.000Z"), 
         ISODate("2015-01-04T00:00:00.000Z"), 
         ISODate("2015-01-05T00:00:00.000Z") 
        ] 
       }, 
       { 
        "_id" : ObjectId("5977f9187dcd6a5f6a9b4b96"), 
        "carrier" : "abc", 
        "flightNumber" : 123.0, 
        "dates" : [ 
         ISODate("2015-01-01T00:00:00.000Z"), 
         ISODate("2015-01-02T00:00:00.000Z"), 
         ISODate("2015-01-03T00:00:00.000Z") 
        ] 
       } 
      ] 
     } 
    ] 
}