How to retrieve first and last elements from MongoDB array and set it as distinct fields?

Viewed 38

My collection:

{
        "_id" : ObjectId("60e46c1dfc320656ffc683b4"),
        "name" : "A",
        "name_test" : "a b c",
        "arr" : [
                "1",
                "2",
                "3"
        ]
}
{
        "_id" : ObjectId("60e46c20fc320656ffc683b5"),
        "name" : "B",
        "name_test" : "B A",
        "arr" : [
                "a",
                "b",
                "c"
        ]
}
{
        "_id" : ObjectId("60e46c26fc320656ffc683b6"),
        "name" : "T1",
        "number" : 1,
        "name_test" : "T1",
        "arr" : [
                "t1",
                "t2",
                "t3"
        ]
}

And I want to extend fields with the first and last elements of array "arr", like:

{
            "_id" : ObjectId("60e46c26fc320656ffc683b6"),
            "name" : "T1",
            "number" : 1,
            "name_test" : "T1",
            "arr" : [
                    "t1",
                    "t2",
                    "t3"
            ],
            "first": "t1",
            "last": "t3"
    }

I am trying this command for Mongo:

db.test_coll.update({}, 
        [{ $set: 
              { first: { $arrayElemAt: [ "$arr", 0 ]}, 
                last: { $arrayElemAt: [ "$arr", -1 ]} }
              },
        ])
                        

I also tried:

db.test_dups.updateMany({$where: "this.arr.length > 1"}, ...

But not successful. I got next error:

[thread1] Error: the update operation document must contain atomic operators :
DBCollection.prototype.updateMany@src/mongo/shell/crud_api.js:568:1

How could I do it? Maybe using PyMongo?


Issue resolution: My mongo was 3.2, and most command were not working in there, so I solved it using PyMongo:

bulk = db.test.initialize_ordered_bulk_op()

cnt = 0
for profiles in db.test.find():
    cnt += 1 
    
    try:
        bulk.find({'_id': profiles['_id']}).update({'$set': {
                'f': profiles['arr'][0],
                'l': profiles['arr'][-1]
            }
        })

        if cnt % 1000000 == 0:
            print("Exectuting", cnt)
            bulk.execute()
            bulk = db.test.initialize_ordered_bulk_op()
    except:
        print(profiles['_id'], " - Did not worked out")
    
try:
    bulk.execute()
except:
    print("Bulk is Empty")
2 Answers
  • $expr and $gt to check arr length should be greater than 1
  • $first and $last operator to select elements from arr
db.test_dups.updateMany(
  { $expr: { $gt: ["$arr", 1] } },
  [{
    $set: {
      first: { $first: "$arr" },
      last: { $last: "$arr" }
    }
  }]
)

Playground


Issue resolution: My mongo was 3.2, and most command were not working in there, so I solved it using PyMongo:

bulk = db.test.initialize_ordered_bulk_op()

cnt = 0
for profiles in db.test.find():
    cnt += 1 
    
    try:
        bulk.find({'_id': profiles['_id']}).update({'$set': {
                'f': profiles['arr'][0],
                'l': profiles['arr'][-1]
            }
        })

        if cnt % 1000000 == 0:
            print("Exectuting", cnt)
            bulk.execute()
            bulk = db.test.initialize_ordered_bulk_op()
    except:
        print(profiles['_id'], " - Did not worked out")
    
try:
    bulk.execute()
except:
    print("Bulk is Empty")
Related