2

Let's say I have these two collections

book: {
    _id: 'aaa'
    name: 'Book 1',
    chapters: [
       0: {
           _id: 'chapter0',
           name: 'Chapter 1',
           pages: [
                0: {
                    _id: 'page0',
                    name: 'Page 1',
                    paragraphs: [
                        0: {
                            _id: 'paragraph0',
                            name: 'Paragraph 1',
                            bookmarks: [
                                 0: {sentence: 3, reader: 'Foo'},
                                 1: {sentence: 8, reader: 'Bar'},
                                 2: {sentence: 14, reader: 'John'}
                            ]
                        }
                    ]
                }
           ]
       }
    ]
}



book: {
    _id: 'bbb'
    name: 'Book 2',
    chapters: [
       0: {
           _id: 'chapter0',
           name: 'Chapter 1',
           pages: [
                0: {
                    _id: 'page0',
                    name: 'Page 1',
                    paragraphs: [
                        0: {
                            _id: 'paragraph0',
                            name: 'Paragraph 1',
                            bookmarks: []
                        },
                        1: {
                            _id: 'paragraph1',
                            name: 'Paragraph 2',
                            bookmarks: [
                                 0: {sentence: 2, reader: 'George'},
                                 1: {sentence: 1, reader: 'Paul'},
                                 2: {sentence: 76, reader: 'John'},
                                 3: {sentence: 54, reader: 'Ringo'}                                 
                            ]
                        }
                    ]
                }
           ]
       }
    ]
}

I want to be able to extract the array bookmarks and attach them to the book collection when getting the result. Something like this would be good:

{
    id: 'aaa'
    name: 'Book 1'
    bookmarks: [{...}, {...}, {...}] //since the first book has 3 bookmarks
},
{
    id: 'bbb'
    name: 'Book 2'
    bookmarks: [{...}, {...}, {...}, {...}] //since the second book has 4 bookmarks
},

And if there are no bookmarks, it should look like:

{
    id: 'aaa'
    name: 'Book 1'
    bookmarks: [{...}, {...}, {...}] //since the first book has 3 bookmarks
},
{
    id: 'bbb'
    name: 'Book 2'
    bookmarks: [{...}, {...}, {...}, {...}] //since the second book has 4 bookmarks
},
{
    id: 'ccc'
    name: 'Book 3'
    bookmarks: [] //third book does not have bookmarks for example
},

I've tried aggregation with this code, but it just separates each bookmark per book and pushes it into the object.

return yield Books.aggregate()
    .unwind('chapters')
    .unwind('chapters.pages')
    .unwind('chapters.pages.paragraphs')
    .unwind('chapters.pages.paragraphs.bookmarks')
    .group({
        _id: '$_id',
        books: {
            $push: {
                _id: '$_id',
                name: '$name',
                bookmarks: '$chapters.pages.paragraphs.bookmarks'
            }
        }
    }).exec()

Can someone point me to the right direction? Thanks!

1 Answer 1

2

Try below aggregate pipeline:

Books.aggregate([
  {
    $unwind: "$book"
  },
  {
    $unwind: "$book.chapters"
  },
  {
    $unwind: "$book.chapters.pages"
  },
  {
    $unwind: "$book.chapters.pages.paragraphs"
  },
  {
    $unwind: {
      path: "$book.chapters.pages.paragraphs.bookmarks",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $group: {
      _id: {
        _id: "$_id",
        book: "$book.name"
      },
      bookmarks: {
        $push: "$book.chapters.pages.paragraphs.bookmarks"
      }
    }
  }
])
Sign up to request clarification or add additional context in comments.

6 Comments

No luck, it's returning the same data i've been getting which is the bookmarks are taking up the results one by one instead of being attached to the book object
It works but one caveat is that it's not returning the book field if bookmarks array is empty. it should still return it but with bookmarks: []. How can i modify the code to get that result?
add preserveNullAndEmptyArrays in last unwind then { $unwind: { path: "$book.chapters.pages.paragraphs.bookmarks", preserveNullAndEmptyArrays: true } },
Oh btw, you should edit your answer to reflect the comment you added here. But i already accepted it
There's one last issue though. The 'bookmarks' array is outside the _id object which I assume is used by $group. Is there any way to not use the _id object and just make it as one object that has id, name and bookmarks?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.