MongoDB $push ObjectId - mongodb

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));

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:
Converting some fields in Mongo from String to Array
mongodb type change to array
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)]]

Related

Newbie get _id of returned where query

Selecting specific item from returned query (newbie)
Using laravel with the https://github.com/jenssegers/laravel-mongodb#query-builder package so the php is a bit off the norm for MongoDB terminology
I query the database like so:
$role_id = Role::where('name', 'Admin')->get();
How do I access the '_id' of the returned query?
I would like to grab the '_id' in a variable
get() returns Illuminate\Support\Collection object. That means you are getting an array of return items. So, in your case, you should iterate $role_id to loop through the items and get _id. Like this -
foreach ($rid as $role_id) {
echo $rid->_id;
}

Is There a way to fetch data from mongodb Collection using in Array function. if array id is string

I have Generating the Dynamic Report from mongodb Collections. I fetch Data from one Collection and e.g client and take all client id in Array e.g ["5b7869dff0be71721f53d2e3","5b7869dff0be71721f53d2e4","5b7869dff0be71721f53d2e3"] When i I fetch data from other collection using In Array e.g {"clientId": { $in: inArray } } it give me empty result. because in array work if i put { "clientId": { $in: [ObjectId('5b785f243cc6c746af635dc8')] } } "ObjectId" word before the id. My Question is how i Put this ObjectId work in the array.
you can use map to map the array to an array of ObjectId
inArray = inArray.map( value => ObjectId(value) );

How to user $in query in mongodb?

I want to fetch records when permission = User.
Below is my colletions:
"_id":ObjectId("59177f050c9db20629f4562"),
"profile":
{
"permissionGroups" : [
"Admin",
"Restaurant",
"Salesperson",
"User"
]
}
Fetch only in permission is User.
Thanks in advance,
Well first, access the permissionGroups array inside profile obj and then run a query simply matching the string like this. You don't need to run a $in unless you have multiple strings in array to match with:
db.getCollection('collection name').find({"profile.permissionGroups" : "User"})
I don't think $in is what you're looking for. $in queries an array against a field, so let's say you search permissionsGroup: {$in: ['User', 'Admin']}, and that would return all records that could find either User or Admin.
In this case you can simply search for permissionsGroups: 'User'. Mongo is smart enough to recognize permissionGroups as an array, and test the given value against the fields in that array.

How to I ensure that all items in an $in clause return a match in MongoDB?

I am working with a set of documents like this:
{
name : "BCC 204",
//etc
}
I have a list of names that I want to map to their DB entries.
For example:
var names = [ "BCC 204", "STEW 101", "SMTH 123" ]
and I want to make a query like this
db.labs.find( { name : { $in: names } } );
But the $in operator does not ensure that each item in the names array matches a result in the db.
(More info, names are unique)
You can't do this in the query. $in will check that a document matches at least one entry in the array given, but it's not going to consider the entire result set. This is a concern you'll need to manage in your application. Given a list of inputs, you will need to retrieve your results then check that given_names - results.map(:name) is empty.
To put it more simply, queries match documents, which compose a result set - they don't match a result set.

Updating multiple MongoDB records in Sails.js

I need to update multiple records in mongodb.
From frontend logic , i got the array of id's as below.
ids: [ [ '530ac94c9ff87b5215a0d6e6', '530ac89a7345edc214618b25' ] ]
I have an array of ids as above , i need to update the folder field for all the records in that array.
I tried passing the id's to mongodb query as below , but still that doesn't work.
Post.native(function(err, collection) {
collection.update({
_id : {
"$in" : ids
}
}, { folder : 'X'}, {
multi : true
}, function(err, result) {
console.log(result);
});
});
Please help.
There seem to be two possible problems.
1) your ids array is not an array of ids, it's an array which has a single element which is itself an array, which has two elements. An array of ids would be `[ 'idvalue1', 'idvalue2']
2) your id values inside of arrays are strings - is that how you are storing your "_id" values? If they are ObjectId() type then they are not a string but a type ObjectId("stringhere") which is not the same type and won't be equal to "stringhere".
There is no reason to use the native method in this case. Just do:
Post.update({id : ids}, {folder : 'X'}).exec(console.log);
Waterline automatically does an "in" query when you set a criteria property to an array, and Sails-Mongo automatically translates "id" to "_id" and handles ObjectId translation for you.
Those strings look like the string representation of mongod ObjectIds, so probably what you want to do is turn them into ObjectIds before querying. Assuming you've corrected your problem with the extra level of nesting in the array, that is:
ids = ['530ac94c9ff87b5215a0d6e6', '530ac89a7345edc214618b25']
Then you want to do something like this:
oids = []
for (var i in ids)
oids.push(ObjectId(ids[i]))
db.c.find({_id: {$in: oids}})
Does that fix your problem?