user3295878
user3295878

Reputation: 861

How to pop() the last element of an array with Aggregate

I have data in below format:

{ 
    "Array1" : [
        "A", 
        "B", 
        "C", 
        "D", 
        "E"
    ], 
    "tag": "X"
}
{ 
    "Array1" : [
        "A", 
        "B", 
        "C", 
        "X", 
        "Y"
    ], 
    "tag": "X"
}
{ 
    "Array1" : [
        "A", 
        "B", 
        "C", 
        "L", 
        "M"
    ], 
    "tag": "U"
}

And, I need to perform a pop command on Array1 during the aggregate command so that the last element is ignored. I am trying the below command:

aggregate([
{$unwind: "$Array1"},
{$group: {_id: "$Array1" count: {$sum: 1}}},
])

Similarly, would it be possible to ignore the first element of the array?

Edit: Expected output:

{
    "A": 3,
    "B": 3,
    "C": 3,
    "D": 1,
    "X": 1,
    "L": 1
}

Upvotes: 0

Views: 2433

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50436

I'm going to skip the PHP translation because it's both late at night for me and also quite trivial. But the basic process is this:

db.collection.aggregate([
  { "$unwind": "$Array1" },
  { "$group": {
    "_id": "$_id",
    "Array1": { "$push": "$Array1" },
    "last": { "$last": "$Array1" }
  }},
  { "$project": {
    "Array1": { 
      "$setDifference": [
        "$Array1",
        { "$map": { "input": ["A"], "as": "el", "in": "$last" } }
      ]
    }
  }}
])

If your array items are not actually unique, or the order is impotant so the "set" operator there messes with this, then do this instead:

db.collection.aggregate([
  { "$unwind": "$Array1" },
  { "$group": {
    "_id": "$_id",
    "Array1": { "$push": "$Array1" },
    "last": { "$last": "$Array1" }
  }},
  { "$unwind": "$Array1" },
  { "$redact": {
    "$cond": { 
      "if": { "$eq": [ "$Array1", "$last" ] },
      "then": "$$PRUNE",
      "else": "$$KEEP"
    }
  }},
  { "$group": {
    "_id": "$_id",
    "Array1": { "$push": "$Array1" }
  }}
])

In either case, you are essentially comparing the $last element found in the array with the whole array and removing that from the selection.

But personally, unless you need this type of operation for further aggregation, then do it in client code. Or wait for the next release of MongoDB where the new $slice operator makes this simple:

db.collection.aggregate([
  { "$project": {
    "Array1": {
      "$slice": [ 
        "$Array1", 
        0, 
        { "$subtract": [
          { "$size": "$Array1" },
          1
        ]}
      ]
    }
  }}
])

All produce ( in varying forms, as with the "set" operation ) :

{
        "_id" : ObjectId("55cb4ef04f67f8a950c7b8fa"),
        "Array1" : [
                "A",
                "B",
                "C",
                "D"
        ]
}
{
        "_id" : ObjectId("55cb4ef04f67f8a950c7b8fb"),
        "Array1" : [
                "A",
                "B",
                "C",
                "X"
        ]
}
{
        "_id" : ObjectId("55cb4ef04f67f8a950c7b8fc"),
        "Array1" : [
                "A",
                "B",
                "C",
                "L"
        ]
}

Upvotes: 2

Related Questions