Deleting a document based off of it's ObjectId [duplicate] - php

I was successful in deleting documents using other fields but could not delete using "_id" field. The PHP page says that the id should be a string (which it is by default), but what I was trying to do is, giving an id of my own which is an integer, and am doing the following:
This is my document structure:
$document = array (
'_id' => new MongoInt32(1),
'cust_id' => 'abc124'
)
This is how I am trying to delete:
$collection->remove(array('_id' => new MongoId(1)), true);
But this is giving me an error. PHP php manual says:
"To remove a document based on its ID, you need to ensure that you pass the ID as a MongoID object rather than just a string:"
But my id is a int and I cant figure out the process to delete the document referenced by the id.
Your help would be appreciated. Thank You.

You've used a normal integer (MongoInt32) as _id field. And MongoInt32 is not the same as MongoID. They are two different classes. You are suppose to delete it with:
$collection->remove( array( '_id' => new MongoInt32(1) ) );
Additional Information:
MongoId is used as value for an _id field if you don't set a value yourself, such as with:
$collection->insert( array( 'cust_id' => 'abc124' ) );
If you retrieve this document, and var_dump() that you will see:
array(2) {
'_id' =>
class MongoId#6 (1) {
public $$id =>
string(24) "51ee74e944670a09028d4fc9"
}
'cust_id' =>
string(6) "abc124"
}
The note in the docs mean that you can't remove that document now with:
$collection->remove( array( '_id' => '51ee74e944670a09028d4fc9' ) );
But instead you will need to use:
$collection->remove( array( '_id' => new MongoID( '51ee74e944670a09028d4fc9' ) ) );
As last point I'd like to raise that you don't really have to use new MongoInt32(1) in the first place, you can just use:
$document = array (
'_id' => 1,
'cust_id' => 'abc124'
);
You only need MongoInt32/MongoInt64 in case you're on a 32-bit platform (or Windows) and need to deal with large numbers.

This should work:
$collection->deleteOne( array( '_id' => new MongoDB\BSON\ObjectId ($_id )) );

"To remove a document based on its ID, you need to ensure that you pass the ID as a MongoID object rather than just a string:"
Normally what the PHP manual states is true but not for you. You have changed the type of your _id to something other than an ObjectId (aka a MongoId).
With this in mind you need to search by that other object which is a MongoInt32:
$db->collection->remove(array('_id'=>new MongoInt32(1)))

Related

Trying to add an array to an associated array

I have an associated array saved in my database that Im saving to a variable called response_cost using the Wordpress function get_post_meta.
$response_cost = get_post_meta( $postID, $metaKey, true );
The array looks something like this:
a:2: {
i:0;a:3:
{s:4:"type";s:6:"months";s:4:"cost";s:0:"";s:8:"modifier";s:1:"=";}
i:1;a:3:
{s:4:"type";s:5:"weeks";s:4:"cost";s:0:"";s:8:"modifier";s:1:"+";}
}
I have a form that I've created which outputs a new array and it's saved in a variable called $add_to_response_cost.
$add_to_response_cost = array (
'type' => $type,
'cost' => $cost,
'modifyer' => $modifyer
);
I'm can't figure out how to add $add_to_response_cost as another instance of $response_cost so that the out put ends up like so:
a:3: {
i:0;a:3:
{s:4:"type";s:6:"months";s:4:"cost";s:0:"";s:8:"modifier";s:1:"=";}
i:1;a:3:
{s:4:"type";s:5:"weeks";s:4:"cost";s:0:"";s:8:"modifier";s:1:"+";}
i:2;a:3:
{ my new array I've constructed via $add_to_response_cost }
}
Any help or direction with this is greatly appreciated.
To understand the problem, first we need to explain a little about how saving arrays in custom fields works
Here we have an array
$array = array(
"0" => array(
"type" => "months",
"cost" => null,
"modifier" => "=",
),
"1" => array(
"type" => "weeks",
"cost" => null,
"modifier" => "+",
)
);
If we decide to save it as a custom field in the database, we use the update_post_meta() function
update_post_meta( 1, 'response_cost', $array );
Before saving it to the database, Wordpress will serialize our array and then put it into the database.
As a result, the array will be saved in the database in the following format
a:2:{i:0;a:3:{s:4:"type";s:6:"months";s:4:"cost";N;s:8:"modifier";s:1:"=";}i:1;a:3:{s:4:"type";s:5:"weeks";s:4:"cost";N;s:8:"modifier";s:1:"+";}}
Then, if we want to get an array, we use get_post_meta()
$myarray = get_post_meta(1, "response_cost", true);
Wordpress will take a serialized array from the database and convert it to a typical array.
Then we can add any data we want to the array and save it back to the database.
$add_to_response_cost = array (
'type' => $type,
'cost' => $cost,
'modifyer' => $modifyer
);
$myarray[] = $add_to_response_cost;
update_post_meta( 1, 'response_cost', $myarray );
Usually this problem occurs when using the get_post_meta function without specifying a key, with only one parameter (ID), then we get arrays without processing and they must first be unserialized
This can also happen when you get an array from a database not through a Wordpress function, but by direct SQL query to the database.
Then you need to unserialize the array first, add data to it and pack it back.
You can try unserialize() to convert it to array.
$result = unserialize($response_cost);
Print_r($result);

YouTube Feed has an object called #attributes how can I access it?

I am trying to get a YouTube RSS feed to work but I am struggling to get one of the attributes I need out of it. I have never seen part of the array starting with an # sign so I think it may be some sort of a special element but I'm not sure. Code below and what I have already tried after.
Feed:
<?php
$xml->entry =
SimpleXMLElement::__set_state(array(
'id' => 'yt:video:DjwM9SHJznM',
'title' => 'JD19AT - Joomla! in der Uni - Community-Arbeit als Lehrveranstaltung',
'link' =>
SimpleXMLElement::__set_state(array(
'#attributes' =>
array (
'rel' => 'alternate',
'href' => 'https://www.youtube.com/watch?v=DjwM9SHJznM',
),
)),
'author' =>
SimpleXMLElement::__set_state(array(
'name' => 'J and Beyond e.V.',
'uri' => 'https://www.youtube.com/channel/UCy6ThiEDnalZOd_pgtpBk1Q',
)),
'published' => '2019-03-30T16:49:53+00:00',
'updated' => '2019-05-09T16:56:18+00:00',
));
?>
Code:
$feed = $youtubeChannelFeed;
$xml = simplexml_load_file($feed);
$html = "";
This works $xml->entry->title;
but this doesn't $xml->entry->link it just says "SimpleXML Object"
As it says object I then tried using both -> arrow and ['attribute'] notation.
I tried escaping the # with a \# but that just caused an error.
How can I traverse the tree and get the value of to #attributes->href ?
The way I always try to remember this is that you can use an arrow or brackets to access data in an array or object.
Array begins with A, but it chooses the one that's does not begin with A. Object is the one left over. That's how I remember it at least.
In this case, although it was calling it a SimpleXMLObject it was actually showing me that it's an array in the print_r. So I had to use brackets to access like so:
$xml->entry->link[0]['href']
I couldn't work out how to access #attributes but I remember now that you don't need to know the name to access it, you can do it using number format too.
If I'm honest I don't really know how I could access the first part with arrows as that appears to be an array too.

How to find all documents where the value of a field is null or empty

I'm trying to write a simple Mongo query to return all documents where the value of a field is null (or an empty array, I'm not sure what you call it).
Here is my query;
db.getCollection('contact').find({'poco.name.email':false})
Here is a screenshot of my collection using RoboMongo;
Ultimately, I need to transfer this to some PHP. So far I have this working;
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
//not sure what goes here.. something like
//'poco.emails' => null,
]);
return Model_Mongo_Contact::getContacts($conditions, $sort, $fields, $limit, $skip);
That's probably going to be harder to answer without more access to the methods.. Or maybe not I am very new to Mongo it might be really obvious.
I'm not PHP expert but I'll be doing in mongo shell as:
db.collection.find({
$and: [
{"poco.email":{$exists: true}},
{"poco.email":{$ne: []}}
]})
Query above will list all documents where poco.name.email is not missing and is not empty.
The basic concept when looking for an "empty" array or even "non-existent" is to use a property of "dot notation" and search where the 0 index of the array does not exist. This can be achieved with using the $exists operator:
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
'poco.emails.0' => array( '$exists' => FALSE )
]);
That condition is true when either there is no property at all, or if it is something other than an array ( therefore no "0" field property ) or indeed an "empty" array ( since there is no content at the first index ).
This works best when the field is actually "indexed". So if in your "normal" structure you have "sub-documents" inside the array element with say a consistent field named "address" which is indexed as "poco.emails.address", then you are best of pointing to that specific indexed property to see if it $exists or not:
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
'poco.emails.0.address' => array( '$exists' => FALSE )
]);
But if the array consists purely of "values" only and no "sub-documents", then simply testing for the 0 index position of the array as initially demonstrated will be enough.

DyanmoDB: not getting the answer I'm expecting using batch_get_item

I am trying to do a batch_get_item to request multiple items from a table. I am following the PHP example in the DynamoDB documentation, but I am not getting the results I'm expecting.
Following is the code:
$batch_array = array ();
$batch_array[]= array ('HashKeyElement' =>
array( AmazonDynamoDB::TYPE_STRING => 'V1L3M5O5L1W8R5B6D2Q1S8V0B3R8M7A6R0X0'));
$options = array (
'RequestItems' => array(
'profile_dev' => array (
'Keys' => $batch_array
)
)
);
$result = $this->db->batch_get_item($options);
Instead of getting the data, I am getting a very long response, and I'm including the relevant information from the tail end of it:
[x-aws-body] => {"RequestItems":{"profile_dev":{"Keys":[{"HashKeyElement":{"S":"V1L3M5O5L1W8R5B6D2Q1S8V0B3R8M7A6R0X0"}}]}}} ) [body] => CFSimpleXML Object ( [__type] => com.amazon.coral.validate#ValidationException [message] => One or more parameter values were invalid: The provided key size does not match with that of the schema ) [status] => 400 ) )
The hashKey for this table is a string. It has a rangeKey, but I am using the hashKey so I can get all the rows matching the hashKey. What am I missing?
The DynamoDB documentation (and SDK samples) have colossal bugs in them. The documentation, and actual SDK code, make use only of the hashKeyElement, but in fact if a table has both a hashKey AND a rangeKey, both must be used.
When I used both the hashKey and the rangeKey, the call worked.
Get (or batch get) requires you to completely define the key of all items you are getting. If you want to retrieve all rows with the same hashKey using a single call, it seems like you're looking for Query.
You don't need to use BatchGet, you should be using Query. Here is an example using the PHP SDK to get all items with the HASH key 'YourHashKey' on table 'YourTable'
// Instantiate the class
$dynamodb = new AmazonDynamoDB();
$response = $dynamodb->query(array(
'TableName' => 'YourTable',
'HashKeyValue' => array( AmazonDynamoDB::TYPE_STRING => 'YourHashKey' ),
));
Reference: http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/LowLevelPHPQuerying.html

get mongodb _id object after upsert with php

is it possible to get the new/updated _id after the query?
example code:
$key = array( 'something' => 'unique' );
$data = array( '$inc' => array( 'someint' => 1 ) );
$mongodb->db->collection->update( $key, $data, array( 'upsert' => true ) );
$key is not holding the new/old _id object and i assume that $data will not either because its just an instruction.
Yes -- It is possible using a single query.
MongoDB includes a findAndModify command that can atomically modify a document and return it (by default it actually returns the document before it's been modified).
The PHP drivers don't include a convenient method for this on the collection class (yet -- check out this bug), but it can still be used (note that my PHP is terrible, so I may very well have made a syntax error in the following snippet):
$key = array( 'something' => 'unique' );
$data = array( '$inc' => array( 'someint' => 1 ) );
$result = $mongodb->db->command( array(
'findAndModify' => 'collection',
'query' => $key,
'update' => $data,
'new' => true, # To get back the document after the upsert
'upsert' => true,
'fields' => array( '_id' => 1 ) # Only return _id field
) );
$id = $result['value']['_id'];
Just in case someone stumbles across this question like I did, Mongo will actually modify the input array when you call MongoCollection->save(); - appending the id to the end.
So, if you call:
$test = array('test'=>'testing');
mongocollection->save($test);
echo $test['_id'];
You will have the mongo id for that object.
I ran into this issue and worked around it by querying back the _id after the upsert. I thought I'd add some of my findings in case they're useful to anyone who comes here searching for info.
When the upsert results in a new document being created in the collection, the returned object contains the _id (here's a print_r of an example):
Array
(
[updatedExisting] => 0
[upserted] => MongoId Object
(
[$id] => 506dc50614c11c6ebdbc39bc
)
[n] => 1
[connectionId] => 275
[fsyncFiles] => 7
[err] =>
[ok] => 1
)
You can get the _id from this:
$id = (string)$obj['upserted'];
However, if the upsert resulted in an existing document being updated then the returned object does not contain _id.
Give this a shot :
function save($data, $id = null) {
$mongo_id = new MongoId($id);
$criteria = array('_id' => $mongo_id);
// Wrap a '$set' around the passed data array for convenience
$update = array('$set' => $data);
$collection->update($criteria, $update, array('upsert' => true));
}
So lets say the passed $id is null, a fresh MongoId is created, otherwise it just converts the existing $id to a MongoId object.
Hope this helps :D
The update method returns an array with the ID of the document UPSERTED:
Array
(
[ok] => 1
[nModified] => 0
[n] => 1
[err] =>
[errmsg] =>
[upserted] => MongoId Object
(
[$id] => 5511da18c8318aa1701881dd
)
[updatedExisting] =>
)
You can also set fsync to true in an update/upsert, to get the _id returned to the object that has been passed to the update.
$save = array ('test' => 'work');
$m->$collection->update(criteria, $save, array('fsync' => true, 'upsert' => true));
echo $save['_id']; //should have your _id of the obj just updated.

Categories