Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongodb aggregate embedded document values

Im Strugling with some aggregation functions in mongodb.

Say I have some documents like this

 [
 {
    _id: "1",
    periods: [
      {
         _id: "12",
         tables: [
           {
              _id: "121",
              rows: [
                  { _id: "1211", text: "some text"},
                  { _id: "1212", text: "some other text"},
                  { _id: "1213", text: "yet another text"},

              ]
           }
         ]
      },
      {
         _id: "13",
         tables: [
           {
              _id: "131",
              rows: [
                  { _id: "1311", text: "different text"},
                  { _id: "1312", text: "Oh yeah"}                      
              ]
           }
         ]
      }
    ]
 },
 {
    _id: "2",
    periods: [
      {
         _id: "21",
         tables: [
           {
              _id: "212",
              rows: [
                  { _id: "2121", text: "period2 text"},
                  { _id: "2122", text: "period2 other text"},
                  { _id: "2123", text: "period2 yet another text"},

              ]
           }
         ]
      }
    ]
 }
 ]

Now I want to use a mongodb query to retrieve all unique texts for one specific top level item.

eg agregate all texts for the top _id 1. This would mean that I want to get all the texts in both of the period subtrees.

expected output would be as follows:

aggregate texts filtering on _id: 1

[
   "some text",
   "some other text",
   "yet another text",
   "different text",
   "Oh yeah"
]

aggregate texts filtering on _id: 2

[
  "period2 some text",
  "period2 some other text",
  "period2 yet another text"
]

So far I have managed to aggregate all the texts , but the end up in multiple arrays and I have not managed to filter them on the id using $match,

My current aggregate query looks like this

[ 
    { "$project" : { "text" : "$periods.tables.rows.text" , "_id" : "$_id"}},
    { "$unwind" : "$text"},
    { "$group" : { "_id" : "$_id" , "texts" : { "$addToSet" : "$text"}}},
    { "$project" : { "_id" : 0 , "texts" : 1}} 
]

It gives me a result loooking something like this

{ "texts" : [ 
        [ [ "Some text" , "Some other text" , "yet another text"] , [ "different text" , "oh yeah" ] ],
        [ [ "period2 some text", "period2 some other text", "period2 yet another text"]]
    ]}

If I add $match: {_id: 1}, no results are returned.

Can anyone please help me out with this one, or point me in a direction on how to solve it. I've been searching for resources, but doesnt seem to find any good documentation on how to use these aggregate functions. The mongodb docs only use simple documents.

PS I know I can do this using mapreduce, but was hoping to be able to use an aggregate function for this.

like image 483
Tommy Avatar asked Sep 13 '13 11:09

Tommy


People also ask

How do I fetch a nested document in MongoDB?

Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.

What passes through a MongoDB aggregation pipeline?

An aggregation pipeline consists of one or more stages that process documents: Each stage performs an operation on the input documents. For example, a stage can filter documents, group documents, and calculate values. The documents that are output from a stage are passed to the next stage.

What does $Set do in MongoDB?

In MongoDB, the $set operator is used to replace the value of a field to the specified value. If the given field does not exist in the document, the $set operator will add the field to the specified value.


1 Answers

Unwind only goes down one level, so you have to call as many times as many levels you have if you do it like

[ 
    { "$project" : { "text" : "$periods.tables.rows.text" , "_id" : "$_id"}},
    { "$unwind" : "$text"},
    { "$unwind" : "$text"},
    { "$unwind" : "$text"},
    { "$group" : { "_id" : "$_id" , "texts" : { "$addToSet" : "$text"}}},
    { "$project" : { "_id" : 0 , "texts" : 1}} 
]

It will work as you expect.

like image 103
attish Avatar answered Sep 21 '22 13:09

attish