I use MongoDB together with PHP. To create a unique document for each user, I set the username to unique with
$db->ensureIndex(array("username" => 1), array("unique" => 1, "dropDups" => 1));
However, if there is a duplicate, the _id value that is being returned for the user is that of the record which got never created and not that of the record which already exists in the db.
Here's the entire function:
function register_user($username, $password, $first_name, $last_name, $email)
{
$m = new Mongo();
$db = $m->users->details;
$db->ensureIndex(array("username" => 1), array("unique" => 1, "dropDups" => 1));
$user_doc = array( "username" => $username, "password" => $password, "first_name" => $first_name, "last_name" => $last_name, "email" => $email);
$db->insert($user_doc);
return $user_doc["_id"]; // here i return the _id
}
How would I go about creating a user database, that has no duplicate usernames?
EDIT:
Here's my temporary solution. I put it right where the insert used to be.
try
{
$db->insert($user_doc,array('safe'=>1));
}
catch ( MongoCursorException $e )
{
// if this did not work, we already have that user inside and want to get his _id
$user = $db->findOne(array('username' => $username, 'password' => $password));
return $user["_id"];
}
If I try to insert it with the safe option, it would always die. Using the try-catch procedure, I try to insert and if it does not work, manually find the _id by username. I'm still not satisfied with this solution, so it would be great if more proficient MongoDB users could give some advice.
First off, you always need that try...catch. The reason you were getting the wrong _id for $user_doc is simply that the driver creates it before sending it to the database. So even if the insert fails it's still on the document.
How would I go about creating a user database, that has no duplicate usernames?
I would start by over-writing the _id field with the user name. The _id is auto-generated as a convenience, but you can set it yourself before you insert.
You will still need to use the try...catch but you will get a specific duplicate key error. You can then use this to correctly handle the case of "that user name already exists".
Here's how I manage to insert if not exists.
$db->update(
array('email' => $email),
array('$setOnInsert' => array('email' => $email)),
array('upsert' => true)
);
This basically just updates when the record exists ("updating" to what it's already set to and $setOnInsert does nothing), but if it doesn't exist, mongo upserts a new record then creates the new key and assigns the value.
Related
There is a problem in inserting to MongoDB database. It is not insert to database in right order.
We read the writing concern in MongoDB:
http://www.php.net/manual/en/mongo.writeconcerns.php
We use mongoDB 2.6 and PHP driver 1.6 with following sample code:
set_message_sample('1');
set_message_sample('2');
set_message_sample($id) {
$connecting_string = sprintf('mongodb://%s:%d/%s', $hosts, $port,$database), // fill with right connection setting
$connection= new Mongo($connecting_string,array('username'=>$username,'password'=>$password)); // fill with proper authentication setting
$dbname = $connection->selectDB('dbname');
$collection = $dbname->selectCollection('collection');
$post = array(
'title' => $id,
'content' => 'test ' . $id,
);
$posts->insert($insert,array("w" => "1"));
Sometimes the result is inserting "2" before "1" to database. We want to inserting in right order (first "1" and next "2") all the times. I also notice that we order the collection with mongoID which automatically set by mongoDB.
We check many options but the problem not solved. How we could solve it? ( How we could disable something like cache or isolate the insert queue to MongoDB.)
So, i think you could insert the second only after the confirmation of the first one. since the insert is asynchronous, you can't be sure who goes first. So you must insert only after the confirmation of the first one.
I have a small piece of code inside a function buts it's not working, even when I pull it out and try it on its own it still doesn't work. I used a MySQL Database Class https://github.com/ajillion/PHP-MySQLi-Database-Class
require_once('class.mysql.php');
$_db = new Mysqlidb('localhost', 'root', '', 'database');
$userCredentials = array(
'userID' => 'asdasda',
'username' => 'dsdasdasd',
'password' => 'v423423c342c23',
'email' => '2423v423#gmail.com',
'userType' => 1,
);
if($_db->insert('users', $userCredentials)) echo 'success';
The correct data is inserted into the database but Success is not displayed, is their a reason for this?
Mysqlidb::insert is wrong. It's return $stmt->insert_id instead of $stmt->execute();. Your query does not use autoincrement value, so, you are getting 0.
Tip from comments:
do not use this library
You got an extra coma at the end of the array you passing as a parameter, I don't think its the problem but still...
Have you tryed to see what is really returned via var_dump?
I am new to MongoDB and trying to perform my first updates.
I have my users collection that is populated by an insert statement. Now, I want to add or insert the field authCode with some data into a specific user.
My problem is that when I perform the following function the whole user data becomes replaced by the information in that update statement. My understanding is that by using upsert I would insert or update a users collection. given that the user already exist I expect just the authCode field to be created or updated.
Could anyone point out what am i doing wrong?
public function addAuthCode( array $userId, $code ) {
$user = $this->db()->user;
$user->update(
$userId,
array( 'authCode' => $code ),
array( 'upsert' => true, 'safe' => true )
);
}
You'll want to take a look at the MongoDB documentation for updates found here: http://docs.mongodb.org/manual/reference/method/db.collection.update/#db.collection.update
Specifically:
Add New Fields
db.bios.update(
{ _id: 3 },
{ $set: {
mbranch: "Navy",
"name.aka": "Amazing Grace"
}
}
)
Notice that in order to add a field, you need to use the $set operator
Chris#MongoLab
I'm trying to use PDO (php data object) to execute queries in a .php file like so:
global $db, $table;
$sth = $db->prepare('INSERT INTO $table(user, timerun, magexp, crimsons, blues, golds, greens) VALUES (:user,:timerun,:magexp,:crimsons,:blues,:golds,:greens) ON DUPLICATE KEY UPDATE timerun=timerun+:timerun, magexp=magexp+:magexp, crimsons=crimsons+:crimsons, blues=blues+:blues, golds=golds+:golds, greens=greens+green');
$sth->execute(array(':user' => $user, ':timerun' => $timerun, ':magexp' => $magexp, ':crimsons' => $cr, ':blues' => $bl, ':golds' => $go, ':greens' => $gr));
echo "success";
However, it doesn't actually update my table. I don't get an error or anything.
Am I doing something wrong or is PDO not supported? The PDO docs said "Beware: Some MySQL table types (storage engines) do not support transactions. When writing transactional database code using a table type that does not support transactions, MySQL will pretend that a transaction was initiated successfully. In addition, any DDL queries issued will implicitly commit any pending transactions."
I'm fairly certain my MySQL tables do support transactions, because the regular 'mysql_query' does work.
Thanks.
I'm not sure about Your code, You have variable inside single quoted string it will not work, You should use double quotation like this:
global $db, $table;
$sth = $db->prepare("INSERT INTO $table(user, timerun, magexp, crimsons, blues, golds, greens) VALUES (:user,:timerun,:magexp,:crimsons,:blues,:golds,:greens) ON DUPLICATE KEY UPDATE timerun=timerun+:timerun, magexp=magexp+:magexp, crimsons=crimsons+:crimsons, blues=blues+:blues, golds=golds+:golds, greens=greens+green:");
$sth->execute(array(':user' => $user, ':timerun' => $timerun, ':magexp' => $magexp, ':crimsons' => $cr, ':blues' => $bl, ':golds' => $go, ':greens' => $gr)); echo "success";
For security:
First of all i would create some associative array with all possible tables from project as keys and then check if table from variable exists as array index using if(isset($validTables[$table])) and then continue the query. For example
<?php
$validTables = array('foo' => true, 'bar' => true, 'other' => true);
if(isset($validTables[$table]))
{
// query logic here
}
else throw new Exception(sprintf('Security error %s table not exists', $table));
Check this code because i wrote it without parsing with php
I am executing the below statement in a class. This code is from
$query = array('_id' => $id, 'lock' => 0);
$update = array('$set' => array('lock' => 1));
$options = array('safe' => true, 'upsert' => true);
$result = $this->_mongo->update($query, $update, $options);
if ($result['ok'] == 1) {
return true;
}
However I do not understand how I would get a duplicate key error.
Can someone explain the possible scenarios and likelihood that I will receive this error?
I have been researching this extensively, cannot find my answer anywhere. So if it is on SO or any other website please share!
Thanks in advance.
Since you're doing an upsert and including _id in your query, you shouldn't be getting any duplicates on that key. This makes me think that you've created a unique index on lock, which isn't going to work for more than 2 documents because you only have 2 values for that field.
If you haven't put a unique index on lock, then you must have a unique index on a field you aren't showing here. That won't work either because on an insert, your upsert is going to set _id and lock only, any other field with an index will be inserted as null. If one of those fields has a unique index, then only a single document can have a null in that field. So when you try and insert another null for that field, you'll get a duplicate key error.