exception: can't temprelease nested lock - php

I am trying to run some server-side JS in Mongo. Operations I am trying to perform are:
db.dropDatabase(); // removing current database
db.copyDatabase('db_dump', 'db', 'localhost'); // substituting it with a dump
Everything works perfectly nice. When I am storing this as a function:
function () {
db.dropDatabase();
return db.copyDatabase('db_dump', 'db', 'localhost');
}
and executing it, everything is also nice and returns me {"ok" : 1}
But when I try to execute this using php driver:
$db->execute("function(){ db.dropDatabase(); return db.copyDatabase('db_dump', 'db', 'localhost'); }");
I get
{
"retval": {
"errmsg":"exception: can't temprelease nested lock",
"code":10298,
"ok":0
},
"ok":1
}
My first though was that I just need to get out of the lock, so I tried this
$db->command(
array(
'$eval' => "function() { db.dropDatabase(); return db.copyDatabase('db_dump', 'db', 'localhost');}"
),
array(
'nolock'=> true
)
);
Nothing else is using database at this point.
Any ideas how to get rid of this error?
I am using Mongo 2.4.4, PHP 5.3.13 and driver 1.2.10
P.S. Tried this on PHP 5.4.16 and the situation is the same

This command cannot be invoked through the eval command (see this thread for some additional discussion on the matter). Rather than use JS methods, you can invoke the copydb command directly with MongoDB::command(). The following script will copy between two databases on the same server, since I omitted the fromhost option:
$m = new MongoClient();
$m->a->drop();
$m->admin->command([
'copydb' => 1,
'fromdb' => 'b',
'todb' => 'a',
]);

Related

Command works in mongodb compass but not in php

_id:1
email:"j#g.com"
This is my collection. When I write
{ email: /^J/i }
in compass it works absolutely fine, but in php
$user_collection->find(
["email" => ['$regex' => "/^j/i"]]
);
finds nothing
In your example /^J/i, the i is an option flag to request case-insensitive search.
When using $regex you need to use a separate options field:
['$regex' => "^j", '$options'=>"i"]

Performing migration programmatically in Doctrine 2

Given I have a path to Doctrine migration classes. How could I perform the migration programmatically in Doctrine 2?
I assume there should be a clean way to perform the migration over the API as it could have be done with earlier versions of Doctrine as described here:
http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/migrations.html
As I don't see any answers, I'll try to provide my solution for performing migration programmatically (with code) in doctrine.
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
use Doctrine\Migrations\Configuration\Migration\ExistingConfiguration;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
use Doctrine\Migrations\MigratorConfiguration;
use Doctrine\Migrations\Provider\SchemaProvider;
use Doctrine\Migrations\Version\Direction;
// connection
$dbParams = [
'dbname' => 'database-name',
'user' => 'database-username',
'password' => 'database-password',
'host' => 'hostname',
'port' => 'port',
'driver' => 'pdo_mysql',
];
try {
$connection = DriverManager::getConnection($dbParams);
} catch (\Doctrine\DBAL\Exception $e) {
echo 'Problem connecting to DB. '.$e->getMessage();
die();
}
// configuration - Be careful what namespace you use
$configuration = new Configuration($connection);
$configuration->addMigrationsDirectory('MyAppNamespace\Migrations', __DIR__ . '/../migrations');
// we want the execution of the migration to make changes to the table doctrine_migration_versions - so the system is aware that executed the migration
$storageConfiguration = new TableMetadataStorageConfiguration();
$storageConfiguration->setTableName('doctrine_migration_versions');
$configuration->setMetadataStorageConfiguration($storageConfiguration);
$dependencyFactory = DependencyFactory::fromConnection(
new ExistingConfiguration($configuration),
new ExistingConnection($connection))
);
$planCalculator = $dependencyFactory->getMigrationPlanCalculator();
// which migration to execute / I assume latest /
$latestMigrationVersion = $dependencyFactory->getVersionAliasResolver()->resolveVersionAlias('latest');
// check if we have at least one migration version to execute
if(!$latestMigrationVersion->equals(new Version(0))){
try {
// so we will execute only latest ONE migration, if you need more, just find a way to list them in the first parameter of method getPlanForVersions()
$planUp = $planCalculator->getPlanForVersions(
[$latestMigrationVersion],
Direction::UP
);
$dependencyFactory->getMetadataStorage()->ensureInitialized();
// do the migration
$dependencyFactory->getMigrator()->migrate($planUp, (new MigratorConfiguration())->setAllOrNothing(false));
}catch (Exception $e){
echo 'There were problems during db-migration.'."\n".$e->getMessage()."\n\n";
}
}
Hope it helps another developer to quick start his prototype.
I tried to be detailed about the code, so people do not waste time into figuring out every single dependency.
Asuming you are using Symfony's DoctrineMigrationsBundle
To migrate to the latest available version use:doctrine:migrations:migrate command.
Here are more available commands.

How can I connect to mongodb replica sets and authenticate by php script?

I use following php script to connect to mongodb replica set:
$conn = new MongoClient("mongodb://mongodb1:27017,mongodb2:27017/?replicaSet=MyRepSet");
$db = $conn->test;
$collection = $db->items;
$item = array(
'name' => 'milk',
'quantity' => 10,
'price' => 2.50,
'note' => 'skimmed and extra tasty'
);
$collection->insert($item);
$conn->close();
This works when I start mongodb without --auth and --key
However, when I start mongodb replica set with --auth and --key, and create a user, like this:
> use test;
> db.addUser("test","123456")
When I try again with the above php script, I get this error:
Uncaught exception 'MongoCursorException' with message 'mongodb3:27017: not authorized for insert on test.items
How can I connect to mongodb replica set and authenticate by php script?
try this
$connection = new Mongo("mongodb://test:123456#127.0.0.1:27017/mongodb1/?replicaSet=MyRepSet");
or if that doesn't work this try
$conn = new MongoClient("mongodb://test:123456#mongodb1:27017,mongodb2:27017/?replicaSet=MyRepSet");
Base on your hint I try following:
on both mongodb1 and mongodb2:
use admin;
db.addUser("admin","123456");
Edit the php connection script:
$conn = new MongoClient("mongodb://admin:123456#mongodb1:27017,mongodb2:27017/?replicaSet=MyRepSet");
It worked !!!! Thanks a lots

PHP Yii: Database connect in runtime

I would like to connect to a second database with Yii at runtime. The database name would come from a database table after the user to login.
I saw in a tutorial I should do this:
$db2 = Yii::createComponent(array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => $emp['database']
));
Yii::app()->setComponent('db2',$db2);
But in my controler when I access Yii::app()->db2 get the error:
Property "CWebApplication.db2" is not defined
What am I doing wrong?
The following works for me:
Yii::app()->mongodb->setActive(false);
Yii::app()->mongodb->setServer('mongodb://localhost:27017');
Yii::app()->mongodb->setDb('db1');
Yii::app()->mongodb->setActive(true);
UPDATED: Try, instead instance, pass configurations:
Yii::app()->setComponent( 'db2', array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => $emp['database']
)
);
Or, you may create special index on params in configurations, such as:
...
'params' => array(
'db2' => null,
),
And the use Yii::app()->params['db2'] = $db2
From this comment:
My problem is not with the creation of the component. Soon after
creating if I access Yii::app()->db2 its works, but when I try to
access via another model or controller I get the error
I think you are setting this component only once somewhere, and then making subsequent requests to different controllers.
You need to put the code, somewhere it is being called EVERYTIME, on every Request. thats how PHP works, there is no "global application state"
by default Yii comes with protected/components/controller.php has base controller for the rest of the app.
my suggestion would be to put your code on the init() method of that controller, so that it always gets called.
You mentioned the database name comes from a table once the user logs in, so you need to save that value in the session, in other to be able to access it in the other requests:
<?php
// After login in
Yii::app()->user->setState('db_name', $db_name);
// in protected/components/controller.php
public function init()
{
if (!Yii::app()->user->isGuest) {
$db2 = Yii::createComponent(array(
'class' => 'EMongoClient',
'server' => 'mongodb://127.0.0.1:27017',
'db' => Yii::app()->user->getState('db_name')
));
Yii::app()->setComponent('db2',$db2);
}
}
Hope it helps, I am assuming many things here :)

MongoDB running command in lithium

I'm trying to run a full text search against some data that is stored in mongoDb using Lithium.
Here is how I am trying to do it in my controller:
$mongodb = Connections::get('default')->connection;
$results = Page::connection()->connection->command(array("text" => "Page", 'search' => "term" ));
I've also tried:
$results = Page::connection()->connection->command(array("text" => "Page", 'search' => "term" ));
However, both of these return: Fatal error: Call to a member function command() on a non-object
What am I doing wrong?
EDIT:
I should add that a simple query on Page is working just fine. For instance:
$results = Page::find('all');
Does return an array with all of the documents in the pages collection like I would expect it to.
UPDATE 2:
I was running all of this from WAMP server. I tried today running it from a linux server, but still got the same exact error. I am really stumped by this and could use some help. Anyone have any ideas?
here is the Page model as it sits now:
<?php
namespace app\models;
use lithium\data\Connections; //added during debugging
use lithium\data\source\MongoDb; //added during debuging
class Page extends \lithium\data\Model {
}
?>
Here is my connection:
Connections::add('default', array(
'type' => 'MongoDb',
'host' => '192.168.48.128',
'database' => 'my_collection'
));
I'm doing it this way:
$plugins = Plugins::connection()->connection->command([
'text' => 'plugins',
'search' => $this->request->query['q']
]);
return compact('plugins');
so I'd recommend checking your configuration - is your model returning other data normally? Is the connection configuration correct?
Got help to figure it out... posting here for others to reference.
proper way of calling it is:
$conn = Model::connection();
$db = $conn->selectDB('db');
$result = $db->command(array(...
Works perfectly when done this way.

Categories