0

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
}
4
  • What do you mean by pop command can you show your expected result? Commented Aug 12, 2015 at 13:24
  • I mean I need to remove the last element of Array1 before unwinding it, so that it becomes [ "A", "B", "C", "L" ]. Commented Aug 12, 2015 at 13:43
  • Do you want to do this for each array1? Commented Aug 12, 2015 at 13:47
  • @user3100115: Yes, since this is Aggregation, it has to apply to all Array1 elements. Commented Aug 12, 2015 at 14:23

1 Answer 1

2

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"
        ]
}
Sign up to request clarification or add additional context in comments.

2 Comments

There are further steps involved in aggregation, and would need this to happen server side, so client side isn't really an option. Also, most likely I'll have to remove last two elements of the array, so that complicates things further.
@user3295878 Well you should have asked that question then if that was your intent. The basic process to do that should be fairly simple to follow, as it is just "iterative" ( repeat the same process again to remove another item ), and also meaning only the second form applies here. Or as I said, grab a development release of MongoDB and hope it is in production before the code you need to run goes live.

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.