2

How can I get only objects in the sales array matching with 2021-10-14 date ?
My aggregate query currently returns all objects of the sales array if at least one is matching.

Dataset Documents

{
    "name": "#0",
    "sales": [{
        "date": "2021-10-14",
        "price": 3.69,
    },{
        "date": "2021-10-15",
        "price": 2.79,
    }]
},
{
    "name": "#1",
    "sales": [{
        "date": "2021-10-14",
        "price": 1.5,
    }]
}

Aggregate

{
  $match: {
    sales: {
      $elemMatch: {
        date: '2021-10-14',
      },
    },
  },
},
{
  $group: {
    _id: 0,
    data: {
      $push: '$sales',
    },
  },
},
{
  $project: {
    data: {
      $reduce: {
        input: '$data',
        initialValue: [],
        in: {
          $setUnion: ['$$value', '$$this'],
        },
      },
    },
  },
}

Result

{"date": "2021-10-14","price": 3.69},
{"date": "2021-10-15","price": 2.79},
{"date": "2021-10-14","price": 1.5}

Result Expected

{"date": "2021-10-14","price": 3.69},
{"date": "2021-10-14","price": 1.5}
0

3 Answers 3

2

How about using $unwind:

.aggregate([
{$match: {    sales: {$elemMatch: {date: '2021-10-14'}    }  }},
{$unwind: '$sales'},
{$match: {'sales.date': '2021-10-14'}},
{$project: {date: '$sales.date', price: '$sales.price', _id: 0}}
])

This will separate the sales into different documents, each containing only one sale, and allow you to match conditions easily.
See: https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

Sign up to request clarification or add additional context in comments.

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
1

You actually need to use a $replaceRoot or $replaceWith pipeline which takes in an expression that gives you the resulting document filtered using $arrayElemAt (or $first) and $filter from the sales array:

[
    { $match: { 'sales.date': '2021-10-14' } },
    { $replaceWith: {
       $arrayElemAt: [
           {
               $filter: {
                   input: '$sales',
                   cond: { $eq: ['$$this.date', '2021-10-14'] }
               }
           },
          0 
       ]
   } }
]

OR

[
    { $match: { 'sales.date': '2021-10-14' } },
    { $replaceRoot: {
       newRoot: {
           $arrayElemAt: [
               {
                   $filter: {
                       input: '$sales',
                       cond: { $eq: ['$$this.date', '2021-10-14'] }
                   }
               },
              0 
           ]
       }
    } }
]

Mongo Playground

1 Comment

if sales array contains >1 members with that date 1 of them is kept. Maybe this is what you need but check this
1

In $project stage, you need $filter operator with input as $reduce operator to filter the documents.

{
  $project: {
    data: {
      $filter: {
        input: {
          $reduce: {
            input: "$data",
            initialValue: [],
            in: {
              $setUnion: [
                "$$value",
                "$$this"
              ],
            }
          }
        },
        cond: {
          $eq: [
            "$$this.date",
            "2021-10-14"
          ]
        }
      }
    }
  }
}

Sample Mongo Playground

Comments

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.