Home > Software design >  Redact nested items in two level arrays
Redact nested items in two level arrays

Time:10-01

Having some issues understanding the $redact stage and cant seem to understand what i’m doing wrong or just missing. I’ve read the docs but it doesn’t go through my specific need or I'm just not understanding it correctly. I want to redact some nested items based on a id/number in a two level deep array. If i omit the array and use a regular key/value it does work. But not when having the values in an array.

I want to redact/remove all the items (articles) where the ids don’t match the input/query id that i provide. If $redact is not suitable for this i will happy take other solutions, but preferably not with $unwind and $group.

If I have a single key/value as authorId as in this playground it does work. https://mongoplayground.net/p/V4mOboXp7zR

On the link above is the result i want to achieve but where the authorIds is an array and not key/values.

But if I have multiple Ids in an array it does not work. As this https://mongoplayground.net/p/pqvJLUfL1f4

Thanks!

Sample data

[
  {
    "title": "one title",
    "articles": [
      {
        content: "lorem ipsum",
        authorIds: [
          1
        ],
        
      },
      {
        content: "bacon ipsum",
        authorIds: [
          2,
          3,
          4
        ]
      },
      {
        content: "hippsum dippsum",
        authorIds: [
          3,
          5
        ]
      },
      {
        content: "hippsum dippsum",
        authorIds: [
          4
        ]
      }
    ],
    
  }
]

Current non working stage

db.collection.aggregate([
  {
    "$project": {
      title: 1,
      articles: 1,
      articleCount: {
        $size: "$articles"
      },
      
    },
    
  },
  {
    "$redact": {
      "$cond": {
        "if": {
          "$or": [
            {
              "$eq": [
                "$authorIds",
                2 // match on this authorId
              ]
            },
            {
              $gte: [
                "$articleCount",
                1
              ]
            },
            
          ]
        },
        "then": "$$DESCEND",
        "else": "$$PRUNE"
      }
    }
  },
  
])

CodePudding user response:

Use setIntersection in redact condition.

aggregate

db.collection.aggregate([
  {
    "$project": {
      title: 1,
      articles: 1,
      articleCount: {
        $size: "$articles"
      }
    }
  },
  {
    "$redact": {
      "$cond": {
        "if": {
          "$or": [
            {
              $gte: [
                "$articleCount",
                1
              ]
            },
            {
              $gt: [
                {
                  $size: {
                    $setIntersection: [
                      "$authorIds",
                      [
                        2
                      ]
                    ]
                  }
                },
                0
              ]
            }
          ]
        },
        "then": "$$DESCEND",
        "else": "$$PRUNE"
      }
    }
  }
])

data

[
  {
    "title": "one title",
    "articles": [
      {
        content: "lorem ipsum",
        authorIds: [
          1
        ]
      },
      {
        content: "bacon ipsum",
        authorIds: [
          2,
          3,
          4
        ]
      },
      {
        content: "hippsum dippsum",
        authorIds: [
          3,
          5
        ]
      },
      {
        content: "hippsum dippsum",
        authorIds: [
          4
        ]
      }
    ]
  }
]

result

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "articleCount": 4,
    "articles": [
      {
        "authorIds": [
          2,
          3,
          4
        ],
        "content": "bacon ipsum"
      }
    ],
    "title": "one title"
  }
]

mongoplayground

  • Related