Sergei R
Sergei R

Reputation: 721

Aggregate data from nested array

I need help with the aggregate framework. I have a model (currencies field can contain more than one object):

const schema = new mongoose.Schema({
  country: { type: String },
  code: { type: String },
  region: [{
    name: { type: String },
    path: { type: Array },
    city: [{
      name: { type: String },
      path: { type: Array },
      latitude: { type: String },
      longitude: { type: String },
    }],
  }],
  currencies: [{
    code: { type: String },
    name: { type: String },
    symbol: { type: String },
  }],
})

And I need to receive all currencies without duplicates. Received data can view like this:

[
  { code: 'string', name: 'sting', symbol: 'string' },
  { code: 'string', name: 'sting', symbol: 'string' },
  ...
]
// or like this:
[
  currencies: [
    { code: 'string', name: 'sting', symbol: 'string' },
    { code: 'string', name: 'sting', symbol: 'string' },
    ...
  ]
]

I try to create a query

Geo.aggregate([
  {
    $group: {
       _id: null,
       currencies: { $addToSet: '$currencies' },
    },
  },
])

but receive this data with duplicates and it has many nested arrays:

[
  {
    "_id": null,
    "currencies": [
      [
        {
          "_id": "5cd9486248989616a411fac5",
          "code": "JPY",
          "name": "Japanese yen",
          "symbol": "¥"
        }
      ],
      [
        {
          "_id": "5cd9491a48989616a411fb47",
          "code": "TRY",
          "name": "Turkish lira",
          "symbol": null
        }
      ],

I try this query:

Geo.aggregate([
  {
    $addFields: {
      code: '$currencies.code',
      name: '$currencies.name',
      symbol: '$currencies.symbol',
    },
  },
])

But I receive error "TypeError: item is not iterable". I need little help )

Db data views like this:

{
    "_id": {
        "$oid": "5c3334a8871695568817eadf"
    },
    "country": "Singapore",
    "code": "sg",
    "region": [
        {
            "path": [
                "Singapore"
            ],
            "_id": {
                "$oid": "5c3366c63d92ac6e531e05c0"
            },
            "city": [],
            "name": "Central Singapore Community Development Council"
        },
        ....
    ],
    "__v": 0,
    "currencies": [
        {
            "_id": {
                "$oid": "5cd948ec48989616a411fb28"
            },
            "code": "BND",
            "name": "Brunei dollar",
            "symbol": "$"
        },
        {
            "_id": {
                "$oid": "5cd948ec48989616a411fb27"
            },
            "code": "SGD",
            "name": "Singapore dollar",
            "symbol": "$"
        }
    ]
}

Upvotes: 0

Views: 133

Answers (2)

db.temp.aggregate([
   {$project : {currencies : 1}}, 
   {$unwind: "$currencies"}, 
   {
      $addFields: {
         currencyHash: {
            $concat : ['$currencies.code', "--", "$currencies.name", "--", "$currencies.symbol"]
         }
      }
   },
   {
      $group: {
         _id: "$currencyHash",
         currency : {
            $first : "$currencies"
         }
      }
   },
   {
       $project: {
          code : "$currency.code",
          name : "$currency.name",
          symbol : "$currency.symbol"
       }
   },
   {
       $project: {
          _id : 0,
          currency : 0
       }
   }
]).pretty()

Upvotes: 0

Kemparaju
Kemparaju

Reputation: 26

In aggregate pipeline first you need to unwind the currencies array and then group them by condition to get desired result.

Geo.aggregate([
 {
   $unwind: '$currencies'
 },
 {
     $group: {
     _id: null,
     currencies: { $addToSet: '$currencies' },
    },
 },
])

For more information you can look into documentation here

Upvotes: 1

Related Questions