0

Here is the data structure for each document in the collection. The datastructure is fixed.

{
  '_id': 'some-timestamp',
  'RESULT': [ 
              {
               'NUMERATION': [ // numeration of divisions
                    {
                                      // numeration of producttypes
                       'DIVISIONX': [{'PRODUCTTYPE': 'product xy', COUNT: 100}] 
                    }
                ]
              }
            ]
}

The query result should be in the same structure but only contain producttypes matching a regular expression.

I tried using an nested $elemMatchoperator but this doesn't get me any closer. I don't know how I can iterate each value in the producttypes array for each division. How can I do that? Then I could apply $pop, $in and $each.

I looked at:

... and more

The solution I want to avoid is writing something like this: collection.find().forEach(function(x) { /* more for eaches */ })

Edit: Here is an example document to copy:

{"_id":"5ab550d7e85d5930b0879cbe","RESULT":[{"NUMERATION":[{"DIVISION":[{"PRODUCTTYPE":"Book","COUNT":10},{"PRODUCTTYPE":"Giftcard","COUNT":"300"}]}]}]}

E.g. the query result should only return the entry with the giftcard:

{"_id":"5ab550d7e85d5930b0879cbe","RESULT":[{"NUMERATION":[{"DIVISION":[{"PRODUCTTYPE":"Giftcard","COUNT":"300"}]}]}]}
Matthias Herrmann
  • 2,650
  • 5
  • 32
  • 66

2 Answers2

1

Using the forEach approach the result is in the correct format. I'm still looking for a better way which does not involve the use of that function - therefore I will not mark this as an answer.

But for now this works fine:

db.collection.find().forEach(
    function(wholeDocument) {
        wholeDocument['RESULT'].forEach(function (resultEntry) {
                    resultEntry['NUMERATION'].forEach(function (numerationEntry) {
                        numerationEntry['DIVISION'].forEach(function(divisionEntry, index) {
                            // example condition (will be replaced by regular expression evaluation)
                            if(divisionEntry['PRODUCTTYPE'] != 'Giftcard'){
                                numerationEntry['DIVISION'].splice(index, 1);
                             }
                        })
                    })
                })
                print(wholeDocument);
    }
)

UPDATE Thanks to Rahul Raj's comments I have read up the aggregation with the $redact operator. A prototype of the solution to the issue is this query:

db.getCollection('DeepStructure').aggregate( [
  { $redact: {
                 $cond: {
                     if: { $ne: [ "$PRODUCTTYPE", "Giftcard" ] },
                     then: "$$DESCEND",
                     else: "$$PRUNE"
                 }
             }
  }
  ]
)
Matthias Herrmann
  • 2,650
  • 5
  • 32
  • 66
  • 1
    The only way I can think of is to come up with an aggregation query with some sort of `$redact` query on it. That might be the only way to keep the original document structure, otherwise just do projection followed by unwinding the array & then apply match conditions – Rahul Raj Mar 23 '18 at 21:14
  • @RahulRaj Thanks, the `$redact` aggregation seems very promising. – Matthias Herrmann Mar 23 '18 at 21:29
0

I hope you're trying to update nested array. You need to use positional operators $[] or $ for that. If you use $[], you will be able to remove all matching nested array elements. And if you use $, only the first matching array element will get removed. Use $regex operator to pass on your regular expression.

Also, you need to use $pull to remove array elements based on matching condition. In your case, its regular expression. Note that $elemMatch is not the correct one to use with $pull as arguments to $pull are direct queries to the array.

db.collection.update(
 {/*additional matching conditions*/},
 {$pull: {"RESULT.$[].NUMERATION.$[].DIVISIONX":{PRODUCTTYPE: {$regex: "xy"}}}},
 {multi: true}

 )

Just replace xy with your regular expression and add your own matching conditions as required. I'm not quite sure about your data set, but I came up with the above answer based on my assumptions from the given info. Feel free to change according to your requirements.

Rahul Raj
  • 3,197
  • 5
  • 35
  • 55
  • I'm sry updating the collection is not an option. The result of the query should not be written to the database. I updated the question with an example document and result which I'm trying to accomplish. – Matthias Herrmann Mar 23 '18 at 19:38