2014-03-01 16 views
0

讓我清楚地表明,如果以前製作過,我會很樂意接受對此問題的答案的鏈接。我不確定如何在搜索引擎中毫不留情地使用它,抱歉。Mongo:在數組字段中按項存在,然後按時間戳字段排序

我有一篇名爲的博客文章集。這些文章有關聯的存儲陣列中的字段標籤(稱爲tags)。他們也有一個帖子時間戳字段

所以收集看起來像這樣(被稱爲on):

[ 
    { 
     _id: '526dd103f00c470200000001', 
     title: 'Lorem ipsum 1.', 
     body: 'Dolor sit amet 1.', 
     tags: ['lorem', 'ipsum'], 
     on: 1000 
    }, 
    { 
     _id: '526fda069909000200000002', 
     title: 'Lorem ipsum 2.', 
     body: 'Dolor sit amet 2.', 
     tags: ['lorem', 'ipsum', 'pinned'], 
     on: 2000 
    }, 
    { 
     _id: '527366a11f58a90200000001', 
     title: 'Lorem ipsum 3.', 
     body: 'Dolor sit amet 3.', 
     tags: ['lorem', 'ipsum'], 
     on: 3000 
    }, 
    // Etc. 
] 

我想文章按日期排序(降序),但我也希望包含標籤「固定」的文章始終顯示在頂部。所以結果集應該是這樣的:

[ 
    { 
     _id: '526fda069909000200000002', 
     title: 'Lorem ipsum 2.', 
     body: 'Dolor sit amet 2.', 
     tags: ['lorem', 'ipsum', 'pinned'], 
     on: 2000 
    }, 
    { 
     _id: '527366a11f58a90200000001', 
     title: 'Lorem ipsum 3.', 
     body: 'Dolor sit amet 3.', 
     tags: ['lorem', 'ipsum'], 
     on: 3000 
    }, 
    { 
     _id: '526dd103f00c470200000001', 
     title: 'Lorem ipsum 1.', 
     body: 'Dolor sit amet 1.', 
     tags: ['lorem', 'ipsum'], 
     on: 1000 
    } 
    // Etc. 
] 

我想要做的是使用蒙戈aggregrations,地圖,減少,或類似的東西給結果排序數據庫本身的內部設置。

我只能做2個查詢(其中一個只包括固定的帖子,另一個包括只有未固定的帖子,都是按日期排序),並使用JavaScript(服務器是nodejs)加入它們,但希望知道更好的方法。

P.S .:我使用node-mongodb-native驅動程序。

謝謝。

+0

你可以用一兩個文檔的樣本編輯你的答案。然後,我們有一些工作。 –

+0

剛剛添加它,@NeilLunn。 –

+0

這是否應該有一個日期字段?你說你想排序。你可以添加他們嗎? –

回答

0

從另一個答案(https://stackoverflow.com/a/22108015/180581)借款:

一種方式來實現這一使用蒙戈的aggregation pipeline是先unwind按標籤的所有文章,然後project他們在有標籤都解開文件創建一個is_pinned: true場「釘」,然後它們回到一起由ID,像這樣:

db.articles.aggregate([ 
    { 
     $unwind: '$tags' 
    }, 
    { 
     $project: 
     { 
      title: 1, 
      body: 1, 
      tags: 1, 
      on: 1, 
      is_pinned: { $eq: ['$tags', 'pinned'] } 
     } 
    }, 

爲了組回相同的文件,我們可以在每個字段上退繞使用$first$push現場重建原始的數組,$max$sum聚集is_pinned($最大工作得很好,並與布爾預期的,所以我更喜歡它):

{ 
     $group: 
     { 
      _id: '$_id', 
      title: { $first: '$title' }, 
      body: { $first: '$body' }, 
      tags: { $push: '$tags' }, 
      on: { $first: '$on' }, 
      is_pinned: { $max: '$is_pinned' } 
     } 
    }, 

然後,終於,我們可以使用is_pinnedsort他們, on

{ 
     $sort: 
     { 
      is_pinned: -1, 
      on: -1 
     } 
    } 
]) 

類似的事情顯然還可以用地圖,減少,但感覺好像有點矯枉過正,和我期望的聚合管道成爲未來大量優化,在某種程度上做一個手動映射 - 減少等o感覺...錯了。

如果您遇到聚合管道/分組限制,則可能需要Map-reduce。在這個答案的時間(MongoDB的2.4.9)的aggregation pipeline documentation states

重要:聚合管道的結果是一個文件,是受BSON文件大小限制,這是目前16兆字節。

此外,$group documentation states

警告:聚合系統目前存儲在存儲器$組操作,處理組的數量較多時,這可能引起問題。

我不知道這是如何適用於map-reduce,但目前map-reduce可能是解決這些潛在問題的一種方法。

由於這些對我來說不是問題,因此這裏介紹的解決方案似乎足夠好。

+0

剛剛意識到,在沒有標籤的情況下展開帖子會導致文檔從管道中丟棄。我不知道如何解決這個問題。當我發現時會更新。 –

0

這應該做的工作,使用聚合:

db.ipsum.aggregate([ 

    {$unwind: "$tags" }, 

    {$project: { 
     _id: "$_id", 
     title: "$title", 
     body: "$body", 
     on: "$on", 
     "tags": "$tags", 
     weight: {$cond: [{$eq: ["$tags", "fixed"]}, 1, 0]} 
    }}, 

    {$group: { 
     _id: { 
      _id: "$_id", 
      title: "$title", 
      body: "$body", 
      on: "$on" 
     }, 
     tags: {$push: "$tags"}, 
     weight: {$sum: "$weight"} 
    }}, 

    {$sort: { weight: -1, "_id.on": -1 }}, 

    {$project: { 
     _id: 0, 
     _id: "$_id._id", 
     title: "$_id.title", 
     body: "$_id.body", 
     on: "$_id.on", 
     tags: "$tags" 
    }} 

]) 

所以主要部分使用$ COND選擇指派權重到您希望您的排序頂部的項目,然後排序適當。

+0

這不是$組不必要的重嗎?我認爲_id應該是'$ _id',否則$ group會在分組時比較標題,主體和字段,當_id應該足夠時。如果我錯了,請糾正我。 –

+0

@ n2liquid-GuilhermeVieira如果您想要原始文檔,請不要使用 –