$ раскрутить дважды, как получить поле с первой размотки?

У меня есть запрос монго, который имеет два раскручивания, чтобы получить массив глав. Мне нужно получить сюжетный "слаг" текущей главы. Я попытался использовать «story.slug»: 1 в части $project, но это просто вернуло мне массив слагов, которыми владеет пользователь.

Документ монго выглядит так:

{
    name: 'Test User',
    slug: 'test_user',
    email: '[email protected]',
    password: 'test',
    story: [
    {
      title: 'Story Title',
      blurb: 'Epic story of a girl',
      slug: 'epic_story_of_a_girl', // Need this ....
      active: true,
      chapters: [{
        title: 'Story',
        chapter: '1',
        content: 'This is the story of a girl. Cried a river and drowned the whole world.',
        slug: '1',
      }]
}

Мой запрос монго выглядит так:

db.users.aggregate([

    {$project: {
         email: 1,
         name: 1,
         slug: 1,
         chapters: "$story.chapters"
     }}, 

    {$unwind: "$chapters"},
    {$unwind: "$chapters"}, 
    {$match: {"chapters.active": true}},
    {$sort: {"chapters._id": -1}},
    {$limit: 20}
])

Результат выглядит следующим образом:

{
         "name" : "Test User",
         "slug" : "test_user",
         "email" : "[email protected]",
         "chapters" : {
                 "title" : "Story",
                 "chapter" : "1",
                 "content" : "This is the story of a girl. Cried a river and drowned the whole world.",
                 "slug" : "1"
         }
 }

Но я хочу, чтобы результат выглядел так или похоже, и я понятия не имею, как это сделать.

{
         "name" : "Test User",
         "slug" : "test_user",
         "email" : "[email protected]",
         "storySlug": "epic_story_of_a_girl" // This thing
         "chapters" : {
                 "title" : "Story",
                 "chapter" : "1",
                 "content" : "This is the story of a girl. Cried a river and drowned the whole world.",
                 "slug" : "1"
         }
 }

person Carlo Cruz    schedule 26.02.2014    source источник


Ответы (1)


Да, я думаю, что вы немного сбились с пути из-за того, что вы сделали на первом этапе проектирования. Это то, что, кажется, сбивает тебя с толку. Рассмотрим следующее:

db.users.aggregate([

    // Try and put a $match phase in here to at least narrow down the items
    // Your later condition is valid even if we are going to get the whole arrays
    {$match: {"chapters.active": true}},

    // First you unwind the story array   
    {"$unwind": "$story"},

    // Then you unwind the chapters array within
    {"$unwind": "$story.chapters"},

    // Match again to "just" get only the active chapters
    {"$match": {"chapters.active": true}},

    // Project into your form
    {"$project": {
        "_id": 0,
        "name": 1,
        "email": 1,
        "storySlug": "$story.slug",
        "activeChapter": "$story.chapters"
    }},         

    // Let's stop here so you can look
    {"$limit": 1}
 ])

Теперь все в порядке, если у вас есть только одна "активная" глава за раз, но в противном случае вам нужно будет нормализовать группу. Что взаимозаменяемо с $project

    {"$group": {
        "_id": {
            "name": "$name",
            "email": "$email",
            "storySlug": "$story.slug"
        },
        "chapters": {"$push": "$story.chapters" }
    }}         

Надеюсь, это прояснит ситуацию.

person Neil Lunn    schedule 27.02.2014
comment
Это сработало довольно хорошо, не знал, что вы можете получить $project позже. Просто нужно было сделать некоторые фильтры $match story.chapters.active. - person Carlo Cruz; 27.02.2014