0

Is there a way to get the index of the last matching element in MongoDB? I'm speaking of an equivalent to JavaScript's Array.prototype.lastIndexOf. I know about $indexOfArray, but I'm looking for the last index, not the first one.

My use case

I've got a collection whose schema looks like this:

{
  // ...
  images: [
    {
      identifier: String,
      imageId: ObjectId
    }
  ]
  // ...
}

I have a record whose got duplicated elements:

{
  // ...
  images: [
    {
      identifier: '0',
      imageId: ObjectId('objectId0')
    },
    {
      identifier: '1',
      imageId: ObjectId('objectId1')
    },
    {
      identifier: '2',
      imageId: ObjectId('objectId2')
    },
    {
      identifier: '0', // <-- duplicated!
      imageId: ObjectId('objectId3')
    },
    // many more elements...
    {
      identifier: '0', // last occurence
      imageId: ObjectId('objectIdN+0')
    },
    {
      identifier: '1',
      imageId: ObjectId('objectIdN+1')
    },
    {
      identifier: '2',
      imageId: ObjectId('objectIdN+2')
    }
  ]
}

I want to remove all the elements before the last occurence of images.identifier: '0'.

Is it possible at all without the usage of JavaScript?

4
  • You can use an aggregation pipeline to get all the duplicate IDS except the last one using $limit & $skip. Once you have the IDs you can delete them one using ObjectID. Commented Nov 2, 2020 at 14:19
  • @Hiren how exactly do I get all the number of elements up until the last duplicate, though? I will need to pass a very specific value to $limit Commented Nov 2, 2020 at 14:26
  • Here are some ideas from which you can think further: Find duplicate urls in mongodb. Commented Nov 2, 2020 at 14:29
  • Do you like to remove "all behind images.identifier: '0'" or "all duplicated identifier"? Commented Nov 2, 2020 at 15:02

1 Answer 1

1

Try this one:

db.collection.aggregate([
   {
      $set: {
         images: {
            $reduce: {
               input: "$images",
               initialValue: [],
               in: {
                  $cond: {
                     if: { $eq: ["$$this.identifier", "0"] },
                     then: ["$$this"], // reset array to current value
                     else: { $concatArrays: ["$$value", ["$$this"]] } // append values
                  }
               }
            }
         }
      }
   }
])
Sign up to request clarification or add additional context in comments.

7 Comments

Won't this result in duplicates as well?
No it does not. It looks for images.identifier: '0' and everything what appeared before in the array is removed. That's how I understood your requirement.
It actually works! I don't see how or why? Can you maybe be more verbose? Sorry for the hassle
@Wernfriend Docmscheit nevermind, I think I understand. Cool, thanks!
Well then $reduce is not that easy to understand in my opinion: It goes over each elements of the array. If identifier: '0' is found then array is reset to current element. Otherwise the current element is appended to the array.
|

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.