0

I am querying data using the aggregate method in MongoDB, but I have a problem. Specifically, I want to replace the value of the price field (with the condition: if this field value is null) with the value of price_option field in the first item from the model field where stock_count is greater than 0. How can I do it?

My code to query collection with aggregate:

const doc = await ProductModel.aggregate([    
    ...
    {
      $group: {
        _id: '$_id',     
        price: { $first: "$price" },
        model: { 
          $addToSet: {
            price_option: '$model.priceOption',
            currency_unit: '$model.currencyUnit',
            stock_count: '$model.stockCount'            
          }        
        }
      }
    },
    {
      $project: {
        _id: 0,
        id: '$_id',       
        price: 1, 
        model: 1   
      }
    }
])

My sample data created in collection:

{
    "price": null,
    "model": [
      {
        "price_option": "200",
        "currency_unit": "dollar",
        "stock_count": 5 
      },
      {
        "price_option": "350",
        "currency_unit": "dollar",
        "stock_count": 0 
      },
      {
        "price_option": "400",
        "currency_unit": "dollar",
        "stock_count": 2 
      },
    ]
  }
]

My desired output is:

{
    "price": "200", <= it would be replace by the first item of remaining items where stock_count greater than 0

    "model": [
      {
        "price_option": "200",
        "currency_unit": "dollar",
        "stock_count": 5 
      },
      {
        "price_option": "350",
        "currency_unit": "dollar",
        "stock_count": 0 
      },
      {
        "price_option": "400",
        "currency_unit": "dollar",
        "stock_count": 2 
      },
    ]
}

1 Answer 1

1
  1. $set - Create price_model field.

    1.1. $filter to filter documents in model array which has stock_count $get 0.

    1.2. first to get the first document from the result in 1.1.

  2. $project - Decorate the output documents. Assign price field with price_model.price_option.

db.collection.aggregate([
  {
    $set: {
      price_model: {
        $first: {
          "$filter": {
            "input": "$model",
            "cond": {
              $gt: [
                "$$this.stock_count",
                0
              ]
            }
          }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      id: "$_id",
      price: "$price_model.price_option",
      model: 1
    }
  }
])

Sample Mongo Playground


For MongoDB version 4.2, you can use $arrayElementAt to get the first element of the array.

db.collection.aggregate([
  {
    $set: {
      price_model: {
        $arrayElemAt: [
          {
            "$filter": {
              "input": "$model",
              "cond": {
                $gt: [
                  "$$this.stock_count",
                  0
                ]
              }
            }
          },
          0
        ]
      }
    }
  },
  {
    $project: {
      _id: 0,
      id: "$_id",
      price: "$price_model.price_option",
      model: 1
    }
  }
])

Sample Mongo Playground ($arrayElementAt)

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

4 Comments

excuse me, what the version of MongoDB are you using?
From MongoDB playground, it is version 5
But $first is only available in the $group stage. It not works for Mongo version 4.2.2
Hi, updated my answer. You can use $arrayElementAt.

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.