2017-07-25 65 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") 
        ] 
       } 
      ] 
     } 
    ] 
}