$lookup 结果使用来自另一个数组的键排序

Posted

技术标签:

【中文标题】$lookup 结果使用来自另一个数组的键排序【英文标题】:$lookup result sorted using a key from another array 【发布时间】:2018-03-29 00:56:18 【问题描述】:

我有以下数据结构:

播放列表集合:


    _id:123,
    artistId:959789,
    title:'playlist1',
    tracks:[trackId:123456,createdDate:03.02.2017,
        trackId:213556,createdDate:04.02.2017,
        trackId:956125,createdDate:05.02.2017]
,

    _id:456,
    artistId:456456,
    title:'playlist2',
    tracks:[trackId:956336,createdDate:03.02.2017,
        trackId:213556,createdDate:09.02.2017,
        trackId:785556,createdDate:011.02.2017]
,

    _id:456,
    artistId:456456,
    title:'playlist3',
    tracks:[trackId:636985,createdDate:01.02.2017,
        trackId:456585,createdDate:06.02.2017,
        trackId:785556,createdDate:09.02.2017]

播放列表曲目数组中的trackId是曲目集合中曲目的_id

曲目集合:

_id:956336,title:'abc',
_id:785556,title:'cdf',
_id:456585,title:'ghi',
_id:213556,title:'xyz',
_id:636985,title:'lmn'

我所做的是使用tracks 数组中的trackId 聚合$lookup,我得到了结果。但是playlistTracks 以其他顺序排序,而不是tracks 数组顺序。


        $match: artistId: 456
,

    $lookup: 
            from: 'tracks',
            localField: 'tracks.trackId',
            foreignField: '_id',
            as: 'playlistTracks'
        
, 

现在我需要的是获取具有以下结构的特定艺术家的播放列表列表: playlistTracks 应该按照tracks 数组中createdDate 的顺序排序。


    _id:456,
    title:'playlist2',
    tracks:[trackId:636985,createdDate:01.02.2017,
        trackId:456585,createdDate:06.02.2017,
        trackId:785556,createdDate:09.02.2017]
    playlistTracks:[_id:956336,title:'abc',
            _id:213556,title:'xyz',
            _id:785556,title:'cdf']
,

    _id:456,
    title:'playlist2',
    tracks:[trackId:636985,createdDate:01.02.2017,
        trackId:456585,createdDate:06.02.2017,
        trackId:785556,createdDate:09.02.2017]
    playlistTracks:[_id:636985,title:'lmn',
            _id:456585,title:'ghi',
            _id:785556,title:'cdf']

【问题讨论】:

【参考方案1】:

所以这些是我添加的文档,用于重现您的用例:

播放列表集合

 
    "_id" : NumberInt(123), 
    "artistId" : NumberInt(959789), 
    "title" : "playlist1", 
    "tracks" : [
        
            "trackId" : NumberInt(123456), 
            "createdDate" : "03.02.2017"
        , 
        
            "trackId" : NumberInt(213556), 
            "createdDate" : "04.02.2017"
        , 
        
            "trackId" : NumberInt(956125), 
            "createdDate" : "05.02.2017"
        
    ]

 
    "_id" : NumberInt(456), 
    "artistId" : NumberInt(456456), 
    "title" : "playlist2", 
    "tracks" : [
        
            "trackId" : NumberInt(956336), 
            "createdDate" : "03.02.2017"
        , 
        
            "trackId" : NumberInt(213556), 
            "createdDate" : "09.02.2017"
        , 
        
            "trackId" : NumberInt(785556), 
            "createdDate" : "11.02.2017"
        
    ]

 
    "_id" : NumberInt(457), 
    "artistId" : NumberInt(456456), 
    "title" : "playlist3", 
    "tracks" : [
        
            "trackId" : NumberInt(636985), 
            "createdDate" : "01.02.2017"
        , 
        
            "trackId" : NumberInt(456585), 
            "createdDate" : "06.02.2017"
        , 
        
            "trackId" : NumberInt(785556), 
            "createdDate" : "09.02.2017"
        
    ]

我将播放列表集合中最后一个重复的 _id 更改为 _id: 457。我不知道您如何拥有两个具有相同 _id 的文档。 _id 字段必须是唯一的。而且我不确定我是否理解正确您想要的结果,因为在您的$match 查询中您写了以下内容:$match: artistId: 456 但在您的数据中没有 artiseId456 em>。

还有这个日期

trackId:785556,createdDate:011.02.2017

从文档 id_456 我更改为

trackId:785556,createdDate:"11.02.2017" 

因为日期看起来很奇怪。看起来您的日期字段也是字符串,因为它看起来肯定不像日期字段。无论哪种方式,$sort 都适用于这两种用例。

tracks 集合我在你的例子中留下了。

所以这似乎是你需要的?

db.playlist.aggregate([

        $match: _id: $in: [456]
,
 $unwind: "$tracks",
$sort: "tracks.createdDate": 1,

    $lookup: 
            from: 'tracks',
            localField: 'tracks.trackId',
            foreignField: '_id',
            as: 'playlistTracks'
        
,

    $group:
      _id: "$_id",
      artistId: $first: "$artistId",
      title: $first: "$title",
      tracks:  $push:   item: "$tracks.trackId", quantity: "$tracks.createdDate"  ,
      playlistTracks:  $push: "$playlistTracks" 
    

])

这会将两个数组排列成相同的顺序。你可以在这里指定$sort: "tracks.createdDate": 1如果你想升序或降序-1顺序

因此,在查找字段之前,您可以展开播放列表数组并对其进行排序。 希望这有效

【讨论】:

实际上我希望使用createdDate$lookup 的结果进行排序。如果我们这样$unwind$sorttracks 数组就会被排序。 对不起,我误解了你的问题,我会更新我的答案。 非常感谢您的努力。我尝试过这个。但没有按照我想要的结果工作【参考方案2】:

按照以下步骤进行

1 unwind the tracks array in playlist collection
2 $lookup match with tracks collection
3 add createddate of tracks array to lookup result as a new key
4 sort based on new key
5 group the results for your requirements

【讨论】:

以上是关于$lookup 结果使用来自另一个数组的键排序的主要内容,如果未能解决你的问题,请参考以下文章

排序数组的键和值,键是Month

使用数组中的键迭代哈希,并对结果求和

编写一个多线程函数实现对数组排序,要求: 1.至少用两个线程 2.数组的元素值可以事先定义好,或者可以从键盘输入(增加一个线程)。 3.用一个线程对数组排序,用另一个线程输出排序结果。 4.保证先排好

PHP从多个json文件中的键值排序结果

合并长度不等的排序数组

重命名数组 PHP 中的键