0

I have tried to do this a number of ways from updateOne, findOneAndUpdate to insert and even tried bulkWrite with no success.

What I have done is I have two collections the users collection and the image_upload collection. I store the users profile image inside image_upload along side all the other images that the user uploads.

What I then store in the users collection is the ObjectID of the image_upload collection that matched the image the user uploaded while creating their account (they can upload a new profile image anytime via edit profile).

So what I would like is the ability to update a ObjectId as I get.

The field personal.profile_id must be an array but is of type objectId in document. Here is the code. I ideally want it to have the ObjectID and not just a string.

$db = static::db()->image_upload;
                    try {
                        $newdata = [
                                    "data"=>
                                            [
                                            "url" => $publlic_url,
                                            "type"=> $mimetype,
                                            "date"=>new MongoDB\BSON\UTCDateTime(),
                                            "profile_pic" => true
                                            ],
                                    "uid"=>New MongoDB\BSON\ObjectId($uid)
                                    ];

                        $oauth_update = $db->insertOne($newdata);

                        $view['newdata'] = $newdata;
                        } catch(MongoResultException $e) {
                            return $response->withStatus(200)
                                ->withHeader('Content-Type', 'application/json')
                                ->write($e->getDocument());

                        }

                        $ids = $oauth_update->getInsertedId();

                        $latest = $db->findOne(array("uid"=>New MongoDB\BSON\ObjectId($uid)));

                        // Check first, last and other personal details.
                        $db = static::db()->users;
                        try {
                        $newdata = ['$set' =>["personal.profile_id"=>New MongoDB\BSON\ObjectId($ids)]];

                        $member_profile = $db->findOneAndUpdate(
                            ['kst'=>New MongoDB\BSON\ObjectId($uid)],
                            ['$push' =>["personal.profile_id"=>['$oid'=>New MongoDB\BSON\ObjectId($ids)]]],
                            [
                                'projection' => 
                                    [ 'personal' => 1 ],
                                "returnDocument" => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER
                            ]);

                        } catch(MongoResultException $e) {
                                echo $e->getCode(), " : ", $e->getMessage(), "\n";
                                var_dump($e->getDocument());
                                return $response->withStatus(200)
                                ->withHeader('Content-Type', 'application/json')
                                ->write(array('code'=>$e->getCode(), 'message'=>$e->getMessage));
                        }

                        return $response->withStatus(200)
                        ->withHeader('Content-Type', 'application/json')
                        ->write(json_encode($member_profile));
halfer
  • 19,824
  • 17
  • 99
  • 186
RussellHarrower
  • 6,470
  • 21
  • 102
  • 204
  • It's a little unclear what you are actually asking here. But the way I see it is `$ids = $oauth_update->getInsertedId()` should actually return an `ObjectId`, and therefore there should be no need to try and "cast" the value again. So you should instead just `['$push' =>["personal.profile_id"=> $ids]]`. Also the "plural" naming is not really clear when it should only be a singular value. And for "pushing an array" you would use the [`$each`](https://docs.mongodb.com/manual/reference/operator/update/each/) modifier if that was the intent. – Neil Lunn Jul 08 '17 at 01:03

1 Answers1

1

There is no work-around for the $push operator requiring an array type. Unfortunately, this is going to require migrating documents in the users collection. Some approaches for doing so are discussed in the following threads:

Alternatively, if you'd rather not migrate all documents in users at once, you can have the code execute two findOneAndUpdate() operations in sequence. The first operation could use $type to only match a document with { "personal.profile_id": { $type: "string" }} and then use $set to assign the most recent image ID. A second operation could then match a document with an array type and use the $push strategy (note that $type cannot be used for detecting an array field). The calling code would then expect exactly one of these operations to actually find and update a document (consider logging an error if that is not the case). This approach would then allow you to start collecting old image IDs for migrated documents, but continue overwriting the field for non-migrated documents.


One other observation based on the code you provided:

['$push' =>["personal.profile_id"=>['$oid'=>New MongoDB\BSON\ObjectId($ids)]]]

$oid looks like extended JSON syntax for an ObjectID. That is neither an update operator nor a valid key to use in a BSON document. Attempting to execute this update via the mongo shell yields the following server-side error:

The dollar ($) prefixed field '$oid' 'personal.profile_id..$oid' is not valid for storage."

If you are only looking to push the ObjectID onto the array, the following should be sufficient:

['$push' => ['personal.profile_id' => new MongoDB\BSON\ObjectId($ids)]]
jmikola
  • 6,892
  • 1
  • 31
  • 61