- New in 1.4 PR1
- Added in this release:
- The Key Feature List:
- Limitations:
- Requirements
- Setup
- Basic usage
- Embedded documents
- Arrays
- Querying
- Creating criteria object from an array:
- Known bugs
- Resources
- Contribution needed!
- Big thanks goes to:
This extension is an almost complete, ActiveRecord like support for MongoDB in Yii It originally started as a fork of MongoRecord extension written by tyohan, to fix some major bugs, and add full featured suite for MongoDB developers.
IMPORTANT Info: I've developed this extension as a hobby project. Now I had stopped using Yii in my hobby and work projects. I'm no longer maintaining this code. My codebase is available for easy fork/download on a github. Feel free to continue my work, YMDS already has active community, you can find support mostly on google groups (described bellow).
PLEASE refer to the new FULL-Documentation page
There is also an google groups for topics related to YMDS, everyone are welcome, to post threads, questions, and support requests there.
Work-around for using the OR
operator with this extension provided in comments
This is the 1.4 preview release 1
New in 1.4 PR1 ¶
The YMDS feature list has grown up recently, some of new ones are:
- MongoDB session handler, for in db session storage
- Ability to set use cursors flag with criteria object
- Support for using
OR
operator with criteria object - Many bugfixes
This is a Preview Release of YMDS 1.4 it is not ready for stable usage I publish it because I need help with testing and code stabilization, anyone are welcome to download, test and submit bug fixes.
Added in this release: ¶
- Few annoying bugs fixed
- Documentation corrects
- Added
EMongoPartialDocument
class, that supports full-featured partial loading of documents from DB - Added fixtures manager, that can replace the Yii default one, and work with Mongo model
- Ability to do massive partial updates of multiple document
The Key Feature List: ¶
Features covered from standard Yii ActiveRecord implementation ¶
- Support of using Class::model()->find / findAll / count / countByAttributes and other Yii ActiveRecord syntax
- Named scopes, along with default scope and parameterized scopes, just like in AR
- Ready to go out-of-box EFFICIENT DataProvider, witch use native php db driver sort, limit and offset features for returning results!
- Model classes and embedded documents inherit from CModel, so you can use every class witch can handle of CModel (ie: Gii form generator)
- Relations support idea/concept/example
- Support for generating CRUD for EMongoDocument models, with Gii!
- Support for generating mongo document models from existing SQL tables!
- Very easy to use criteria object, you don't have to create complex MongoDB query arrays!
MongoDB related feature list ¶
- Support of schema-less documents with Yii standard rules and validation features
- Embedded/Nested document support (Embedded documents have their own Model classes with their own rules and other methods)
- (almost, limited only by MongoDB 4MB limit of single document) endless document embedding/nesting
- Lazy loading/creating of embedded documents
- Ability to set FSync and/or Safe flag of DB write operations on different scopes, globally, on model level, and on single model object
- *Ability to use efficient MongoDB Cursors instead of raw arrays of results, returned by the findAll methods**
- MongoDB GridFS feature support, thanks to work of: Jose Martinez and Philippe Gaultier
- Support for using any other than _id field as a Primary Key, for a collection
- Support to have different models in single collection!
- automated efficient index definition for collections, per model
- Support "Soft" documents, documents that do not have fixed list of attributes
- Ability to do Extreme Efficent document partial updates, that make use of MongoDB
$set
operator/feature - Support for PHP Mongo driver versions below 1.0.5
- Support for partial loading of documents from DB
Limitations: ¶
- The main limitations are only those present in MongoDB itself, like the 4mb data transfer limit. But That's not a big deal either.
- In it's current incarnation, This extension does NOT work with the "$or" criteria operator. When we get it working we will remove this line and add an example.
IMPORTANT: The version on GitHub is more up to date as fixes are pushed to the project. This may or may not get updated on a regular basis
Requirements ¶
- Yii 1.1.5 is required
- MongoDB latest stable is recommended. Untested with older versions.
Setup ¶
In your protected/config/main.php config file. Comment out (or delete) the current 'db' array for your database in the components section, and add the following to the file:
'import' => array(
...
'ext.YiiMongoDbSuite.*',
),
'components' => array(
...
'mongodb' => array(
'class' => 'EMongoDB',
'connectionString' => 'mongodb://localhost',
'dbName' => 'myDatabaseName',
'fsyncFlag' => true,
'safeFlag' => true,
'useCursor' => false
),
),
- ConnectionString: 'localhost' should be changed to the ip or hostname of your host being connected to. For example
if connecting to a server it might be
'connectionString' => 'mongodb://username@xxx.xx.xx.xx'
where xx.xx.xx.xx is the ip (or hostname) of your webserver or host. - dbName: is the name you want the collections to be stored in. The database name.
- fsyncFlag if is set to true, this makes mongodb make sure all writes to the database are safely stored to disk. (as default, true)
- safeFlag if is set to true, mongodb will wait to retrieve status of all write operations, and check if everything went OK. (as default, true)
- useCursors if is set to true, extension will return EMongoCursor instead of raw pre-populated arrays, form findAll* methods, (default to false, for backwards compatibility)
That's all you have to do for setup. You can use it very much like the active record. Example:
$client = new Client();
$client->first_name='something';
$client->save();
$clients = Client::model()->findAll();
Basic usage ¶
Just define following model:
class User extends EMongoDocument
{
public $login;
public $name;
public $pass;
// This has to be defined in every model, this is same as with standard Yii ActiveRecord
public static function model($className=__CLASS__)
{
return parent::model($className);
}
// This method is required!
public function getCollectionName()
{
return 'users';
}
public function rules()
{
return array(
array('login, pass', 'required'),
array('login, pass', 'length', 'max' => 20),
array('name', 'length', 'max' => 255),
);
}
public function attributeLabels()
{
return array(
'login' => 'User Login',
'name' => 'Full name',
'pass' => 'Password',
);
}
}
And thats it! Now start using this User model class like standard Yii AR model
Embedded documents ¶
NOTE: For performance reasons embedded documents should extend from EMongoEmbeddedDocument instead of EMongoDocument
EMongoEmbeddedDocument is almost identical as EMongoDocument, in fact EMongoDocument extends from EMongoEmbeddedDocument and adds to it DB connection related stuff.
NOTE: Embedded documents should not have a static model() method!
So if you have a User.php model, and an UserAddress.php model which is the embedded document. Lest assume we have following embedded document:
class UserAddress extends EMongoEmbeddedDocument
{
public $city;
public $street;
public $house;
public $apartment;
public $zip;
public function rules()
{
return array(
array('city, street, house', 'length', 'max'=>255),
array('house, apartment, zip', 'length', 'max'=>10),
);
}
public function attributeLabels()
{
return array(
'zip'=>'Postal Code',
);
}
}
Now we can add this method to our User model from previous section:
class User extends EMongoDocument {
...
public function embeddedDocuments()
{
return array(
// property name => embedded document class name
'address'=>'UserAddress'
);
}
...
}
And using it is as easy as Pie!
$client = new Client;
$client->address->city='New York';
$client->save();
it will automatically call validation for model and all embedded documents! You even can nest embedded documents in embedded documents, just define embeddedDocuments() method with array of another embedded documents IMPORTANT: This mechanism uses recurrency, and will not handle with circular nesting, you have to use this feature with care :P
Arrays ¶
You easily can store arrays in DB!
Simple arrays
- just define a property for an array, and store an array in it.
Arrays of embedded documents
- there is no way (that i know) where i can easily provide mechanism for this, you have to write Your own
- This is how I accomplish it for now:
// add a property for your array of embedded documents
public $addresses;
// add EmbeddedArraysBehavior
public function behaviors()
{
return array(
array(
'class'=>'ext.YiiMongoDbSuite.extra.EEmbeddedArraysBehavior',
'arrayPropertyName'=>'addresses', // name of property
'arrayDocClassName'=>'ClientAddress' // class name of documents in array
),
);
}
So for the user, if you want them to be able to save multiple addresses, you can do this:
$c = new Client;
$c->addresses[0] = new ClientAddress;
$c->addresses[0]->city='NY';
$c->save(); // behavior will handle validation of array too
or
$c = Client::model()->find();
foreach($c->addresses as $addr)
{
echo $addr->city;
}
Querying ¶
This is one of the things that makes this extension great. It's very easy to query for the objects you want.
// simple find first. just like normal AR.
$object = ModelClass::model()->find()
Now suppose you want to only retrieve users, that have a status of 1 (active). There is an object just for that, making queries easy.
$c = new EMongoCriteria;
$c->status('==', 1);
$users = ModelClass::model->findAll($c);
and now $users will be an array of all users with the status key in their document set to 1. This is a good way to list only active users. What's that? You only want to show the 10 most recent activated users? Thats easy too.
$c = new EMongoCriteria;
$c->active('==', 1)->limit(10);
$users = ModelClass::model->findAll($c);
It's that easy. In place of the 'equals' key, you can use any of the following operators
- 'greater' | >
- 'greaterEq' | >=
- 'less' | <
- 'lessEq' | <=
- 'notEq' | !=, <>
- 'in' |
- 'notIn' |
- 'all' |
- 'size' |
- 'exists' |
- 'type' | // BSON type see mongodb docs for this
- 'notExists' |
- 'mod' | %
- 'equals' | ==
- 'where' | // JavaScript operator
*NOTICE: the $or operator in newer versions of mongodb does NOT work with this extension yet. We will add it to the list above when it is fixed.Newer versions of mongo db will work, just not the $or operator. For examples and use for how to use these operators effectively, use the MongoDB Operators Documentation here.
Here are a few more examples for using criteria:
// first you must create a new criteria object
$criteria = new EMongoCriteria;
// find the single user with the personal_number == 12345
$criteria->personal_number('==', 12345);
// OR like this:
$criteria->personal_number = 12345;
$user = User::model->find($criteria);
// find all users in New York. This will search in the embedded document of UserAddress
$criteria->address->city('==', 'New York');
// Or
$criteria->address->city = 'New York';
$users = User::model()->findAll($criteria);
// Ok now try this. Only active users, only show at most 10 users, and sort by first name, descending, and offset by 20 (pagination):
// note the sort syntax. it must have an array value and use the => syntax.
$criteria->status('==', 1)->limit(10)->sort(array('firstName' => EMongoCriteria::SORT_DESC))->offset(20);
$users = User::model()->findAll($criteria);
// A more advanced case. All users with a personal_number evenly divisible by 10, sorted by first name ascending, limit 10 users, offset by 25 users (pagination), and remove any address fields from the returned result.
$criteria->personal_number('%', array(10, 0)) // modulo => personal_number % 10 == 0
->sort(array('firstName' => EMongoCriteria::SORT_ASC))
->limit(10)
->offset(25);
$users = User::model()->findAll($criteria);
// You can even use the where operator with javascript like so:
$criteria->fieldName('where', ' expression in javascript ie: this.field > this.field2');
// but remember that this kind of query is a bit slower than normal finds.
Regexp / SQL LIKE replacemt ¶
You can use native PHP Mongo driver class MongoRegex, to query:
// Create criteria
$criteria = new EMongoCriteria;
// Find all records witch have first name starring on a, b and c, case insensitive search
$criteria->first_name = new MongoRegex('/[abc].*/i');
$clients = Client::model()->findAll($criteria);
// see phpdoc for MongoRegex class for more examples
for reference on how to use query array see: http://www.php.net/manual/en/mongocollection.find.php
Creating criteria object from an array: ¶
// Example criteria
$array = array(
'conditions'=>array(
// field name => operator definition
'FieldName1'=>array('greaterEq' => 10), // Or 'FieldName1'=>array('>=', 10)
'FieldName2'=>array('in' => array(1, 2, 3)),
'FieldName3'=>array('exists'),
),
'limit'=>10,
'offset'=>25,
'sort'=>array('fieldName1'=>EMongoCriteria::SORT_ASC, 'fieldName4'=>EMongoCriteria::SORT_DESC),
);
$criteria = new EMongoCriteria($array);
// or
$clients = ClientModel::model()->findAll($array);
Known bugs ¶
- Remember, this is not complete yet. So at this stage, it can have some ;]
- If you find any please let me know
- As said before, it does not work with the OR operators
Resources ¶
- Project page on GitHub
- Report a BUG
- MongoDB documentation
- On-Line version of this documentation
- PHP MongoDB Driver docs
- Standard Yii ActiveRecord Documentation
Contribution needed! ¶
- I'm not English native speaker, need someone who can correct/rewrite/write my documentation and/or PHPDoc's in code
- Any help would be great :)
- Contact me: darek.krk on a gmail dot com or via PM
Big thanks goes to: ¶
- tyohan: for first inspirations and idea of extension
- luckysmack: for big help with testing and documentation
- Jose Martinez and Philippe Gaultier, for implementing and sharing GridFS support
- Nagy Attila Gábor, for big help with new functionality and testing
congrants
Great job! much encouragement
Nice work
Very impressive...
NOTE: on the first paragraph the "MongoDB" has wrong link (http://http//www.mongodb.org)
Changes
I'm now writing PHPUnit test cases, for this Suite, so interface may change in feature, if unit tests will show up some bugs.
Very good!
Impressive job, thanks to you I stay up to 3 AM, MongoDB is unreal. I'll follow your work very close.
Thanks for sharing and for your efforts.
Thx
Thx for all good words about this ext, and merry Christmas, for everyone ;)
Good bye mysql
This is what i need. I started writing my own mongo AR for yii, but i found this module very usefull. However im working on model generator (with class annotations) which will work with this extension. I will publish it when ready.
Work-around for using $or operator
For using $or operator with MongoDB you can use this work-around:
// Create criteria like normal (only two conditions are supported by the MongoDB itself $c = new EMongoCriteria(); $c->firstField = 1; $c->secondFiled('>=', 2); $documents = ModelClass::model()->getCollection->find( array('$or' => $c->getConditions()) // This will produce firstField = 1 OR secondField >= 2 ); $models = ModelClass::model()->populateRecords($documents);
I want to use mysql "in" operation, can I?
I want to query some records send by some users in user collection, How can I do?
Think you!
@bitshine
Yes You can, just:
$criteria = new EMongoCriteria(); $criteria->fieldName('in', array(/* ... values to search for ... */)); $results = ModelClass::model()->findAll($criteria);
How can I get the query statement?
canni, Very thanks for your reply!
How can I get the query statement?
@bitshine
Build Yours criteria object and do:
How can I execute a command not using ActiveRecord way?
@cannni I am not want to get the criteria array, but the full mongodb statemant, like sql statement in mysql.
And how can I execute a query not use ActiveRecord way, before I want update multi records in batch.
I am not a English native speaker also, may be not say in the right way.
please contact me bitshine at gmail, Thank you!
I want to use $push command
I means I need http://www.mongodb.org/display/DOCS/Updating#Updating-$push and push all.
@bitshine
@bitshine, ok, I'll try to add support, but please use a github bug tracked for this, and fill up a feature request, I'm not reading comments on a regular basis.
PS You always can use
ModelClass::model()->getCollection()->update('$push'=>array(...));
Feedback? :)
I've not suspected that this extension will became that popular, that was a big nice surprise to me :)
If any of You have used this extension in some production sites, let me know, I would like to see this in action, not only in my projects.
This kind of feedback, will keep me motivated to work on ext and keep it updated :)
Best Regards,
canni
Production Site
I'll potentially be using this on a production, large-traffic site soon. Will let you know if/when that happens (once we decide to migrate some/all of our data to Mongo). In the mean time, keep up the good work!
Querying null
How do I make a "IS NULL" query?
I thought it was something like $criteria->fieldName('null'), but that doesn't work.
Please help.
Querying null
Sorry... found out to be 'exists' and 'notExists'.
Great extension.
@mschmidt
Hey,
testing is field value is null, it's not the same as exists/notExists ;)
If You want to test is fields have value: null You have to use
//is null $criteria->fieldName = NULL; // is not null $criteria->fieldName('!=', NULL);
exists
andnotExists
checks is field name is declared/not declared, with any value, in found documentsHint
There is a little lack in documentation about indexing, ensureIndexes should be called before calling
parent::init()
, or declared as a normalprotected $ensureIndexes = true|false;
field, otherwise the mechanism will always run on every model creation.softAttribute problem
Might be a bug on removing a softAttribute: Unset($this->mySoftAttr);
I had to remove line 83/84 from EMongoSoftDocument.php, because _attributeNames not exists....
public function __unset($name) { ... unset($this->softAttributes[$name]); //$names = array_flip($this->_attributeNames); //unset($this->_attributeNames[$names[$name]]); ... }
@joblo
Thanks for pointing that out, that was left from previous implementation, fixed in current devel branch.
I personally do not use/like soft documents feature, it was added because some users requested it ;)
EMongoDBCache
Hi canni,
it would be nice if you include my new extension EMongoDBCache in your suite.
I think in most cases a Yii developer that uses mongoDB will use YMDS.
For other developer I will publish a version without using 'EMongoDB' class.
Best regards
joblo
Lack of time recently :/
Hey all, sorry for so long wait with YMDS development process, but I'm now killed with amount of work, and YMDS is only my hobby project, I think I'll be free to back in develop of YMDS in about 1,5 week.
cheers,
canni
Migration Compatible?
Is YiiMongoDbSuite compatible with CDbMigration?
Since we use AR objects to access mongodb, if we change the AR properties, they return null for a document. Every document in the collection would have to be updated on migration Up() and Down().
@ agentshark
Since Yours AR object are Yours schema, the only migration tool You need is a version control system :) I know that You can use migration too, but from logic point of view, it is pointless, since You can use mass updates features provided in YMDS.
@canni
But I will run my mass update at the same point as a "migration". Yii now provides native migration with CDbMigration running from yiic. I want to have automated deployment from dev to live server with mongodb. How is it possible?
Using AR creates an object layer over mongodb and both have to be updated. If my AR is version 1 and stores many version 1 documents in my live server. Now in my development server, I create AR version 2 (adding/deleting/renaming AR fields). I will need to run a "migration" (mass update) to set all my version 1 documents to look like version 2. The db can not loose data!!
Does anyone understand what I am trying to say?
@agentshark
The path You should follow is:
MongoDB Http session storage
Hey all,
I've recently added EMongoHttpSession class, for session storage in Mongo, but I have no time to test if it works correctly.
The code is in initial stage without docblocks in f/sessionHandler branch on github.
You're welcome to test it a bit, and give me some feedback, if everything will be okay I'll add documentation, and put this feature in upcoming release.
Cheers,
canni
PHP error v 1.4 pr1
Declaration of EMongoGridFS::update() should be compatible with
that of EMongoDocument::update() in file
"...\YiiMongoDbSuite\EMongoGridFS.php" on
line 314
Please fix in the next release.
Handling of 'or'
In your EMongoCriteria you handle the 'or' operator in the same way as the other operators.
foreach($conds as $operator => $value $this->_conditions[$fieldName][$operator] = $value;
So I can't do something like I would do when using '$or' in direct php mongoDB syntax.
$criteria = array( '$or' => array( array('expire' => 0), array('expire' => array('$gt'=> $time)), ), ),
You expect a fieldname as first item, not an operator 'or'.
But maybe I'm wrong ... or can you change this behavior?
fix for 'Declaration of EMongoGridFS::update() should be compatible with that of EMongoDocument::update()' error
@#3892 the update method in the parent class (EMongoDocument) expects 2 arguments. the update method in the EMongoGridFS class only has 1.
you can fix it by changing the method in the EMongoGridFS to look like this:
public function update(array $attributes=null, $modify = false)
this is how i fixed it (i ran into the same problem today)
So happy that my extension help you to develop a better one.
Great extension, and I'm so happy that my extension inspired you to develop a better extension. Please continue your great job. :)
Query operators are case sensitive*
When using php 5.x in strict mode the query operators wont all work. In the criteria class is an array with the operators but they are all in lowercase. Maybe an idea to mention this in the manual. Correct list of operators is:
- 'greater' - 'greatereq' instead of 'greaterEq' - 'less' - 'lesseq' instead of 'lessEq' - 'noteq' instead of 'notEq' - 'in' - 'notin' instead of 'notIn' - 'all' - 'size' - 'exists' - 'type' - 'notexists' instead of 'notExists' - 'mod' - 'equals' - 'where'
CUniqueValidator
Great! I found it can't use CUniqueValidator rule so far now.
Work-around for using the OR operator
Work-around for using the OR operator is not found in the comments anymore (it got deleted?)
I have been using this regex solution which works for me (when working with strings):
board:/ai|uai/
avg 0.000650s
board:/^(uai|ai)$/
avg 0.000780s
How do you define between soft and hard attributes
Hi,
I have been browsing your documentation but you seem to treat class variables all the same. There is no need to pre-define a schema. This is a problem since I have classes in my Yii project which use non-db variables.
I was wondering how do you fill the metaData array that Yii uses in SQL if mongo has no schema?
Ok I see
I see now you use reflection of public attributes.
some questions
hi canni : thanks for your great extension!
want to know if i can use both RDBMS and the Mongodb in one system , the relation i just use method declaration but the yii 's way(which return some arrays ) , ie:
in User AR class
public function addresses() { return Address::model()->findAllByAttributes(array('attribute_with_client_id'=>$this->primaryKey())); }
the Address is MongoDocument . this is an one to many relation example ,other relations implement the same way . i need some advice .
and the softdocument is very useful , little advice: when a function accept an array which all elements is string ,i will use this way :
if (is_string($params) || is_array($params)) { //you may be trim every array item $params = is_string($params) ? explode(',', $params) : $params; } else{ // throw some exception ,tell the caller parameter is invalid }
now i can use such way to call the function:
$model = new MixedModel();
$model->initSoftAttributes(array('field2', 'field3'));
///or
$model->initSoftAttributes('field4,field5');
why lost $criteria parameter in findByAttributes and findAllByAttributes
In EMongoDocument Class , the findByAttributes and findAllByAttributes method has only one parameter, but in the comment, also I think is needed, should add the $criteria parameter. And these two methods also lost trace log code. See the original code:
/** * Finds document with the specified attributes. * * See {@link find()} for detailed explanation about $condition. * @param mixed $pk primary key value(s). Use array for multiple primary keys. For composite key, each key value must be an array (column name=>column value). * @param array|EMongoCriteria $condition query criteria. * @return the document found. An null is returned if none is found. * @since v1.0 */ public function findByAttributes(array $attributes) { $criteria = new EMongoCriteria(); foreach($attributes as $name=>$value) { $criteria->$name('==', $value); } return $this->find($criteria); }
may should be like this:
public function findByAttributes(array $attributes, $criteria=null) { Yii::trace(get_class($this).'.findByAttributes()','ext.MongoDb.EMongoDocument'); $criteria = new EMongoCriteria($criteria); foreach($attributes as $name=>$value) { $criteria->$name('==', $value); } return $this->find($criteria); }
YiiMongoDBSuite Nested Embedded documents
How to make Nested Embedded Documents???
http://pastebin.com/raw.php?i=wmBydGSR
Info
Please read the info on top of this page, this project is free for take-over.
Dynamic attribute defination.
By defining attributes by properties, you lost one of the biggest privilegies of MongoDB, that can have non regular structure.
What if add new method, that will add custom attributes in protected property $_attributes like in CActiveRecord..
On save code might look like this.
$user = new User; $user->name = 'John'; $user->surname = 'Backer'; $user->addCustomAttribute('age'); $user->age = 15; OR $user->setCustomAttribute('age', 15); $user->save();
And on find:
$user = User::model()->findByPk(....); echo $user->age;
Hopefully my advice will help you,
MG.
Possible performance issue
Great extension!
I hope you allow me to give you a small piece of advice :)
Determining meta data for databases is usually very slow. It's the same for mongo. It's the reason Yii caches it by default.
Depending on your server a call MongoCollection::getIndexInfo() can take 500ms or more to complete. Since you are doing it in your init() function on every page, this will cause serious issues when you are running under higher load (trust me, we experienced it :) ). Best thing is to just use the Yii::app()->cache to temporary cache the actual data so that you can just load it out of the cache for most pageviews.
We just did:
$name = dbName . collectionName; $indexes = Yii::app()->cache->get($name); if (!is_array($indexes)) { <determine indexes the regular way> Yii::app()->cache->set($name, $indexes, 1800); } ...
This gives you a huge performance boost for almost no work.
Is it OK to use this extension in production environment?
Please let me if you have found it good enough to use in a production environment.
Thanks!
good enough for production environment
yes it is.
see Yii-powered Applications: v-ticket.at
Definitely production ready :)
It definitely is :)
Besides the fact that caching was added here and there (see my previous comment) and a new version of deleteByPk to mimic the default behavior (Yii's CActiveRecord implementation of it does not call before/afterDelete) it is being used as is and working very good.
CActiveDataProvider Compatibality
Can this work together with CActiveDataProvider?(asked from a beginner, because I just learned how to use data provider today:) ) It seems it's not mentioned in the Manual.
Is this question make sense?
CActiveDataProvider Compatibality
Can this work together with CActiveDataProvider? -> Yes it does for sure; I am using MongoDB with MySQL.
Is this question make sense? -> Not really since you are using Yii where compatibility and interoperability matters.
fork
anyone forked this extension ?
Forked? Yes - at github
https://github.com/mintao/YiiMongoDbSuite
I found a bug when using EMongoUniqueValidator in update.
When I update a record, such as user and I set the field email unique.
I update the username and the email not modified, then it will show error.
Here is my bugfix for it.
class EMongoUniqueValidator extends CValidator { public $allowEmpty=true; public function validateAttribute($object, $attribute) { $value = $object->{$attribute}; if($this->allowEmpty && ($value === null || $value === '')) return; $criteria = new EMongoCriteria; $criteria->{$attribute} = $value; $count = $object->model()->count($criteria); //if($count !== 0) // $this->addError( // $object, // $attribute, // Yii::t('yii', '{attribute} is not unique in DB.') //); //$count = $object->model()->count($criteria); $obj = $object->model()->find($criteria); if( ! empty($obj)) { if($object->getIsNewRecord() || ($obj->id != $object->id)) $this->addError($object, $attribute, Yii::t('yii', '{attribute} is not unique in DB.')); } } }
Re: bug in unique validator
Re: #7485 by @elsonwu
The performance that would occur in your fix is not ideal, as your solution would issue a count and a find for every unique validation, and a find request is already less performant than a count request.
I suggest you instead use the patch I provide here:
https://github.com/intel352/YiiMongoDbSuite/commit/65f7ae77c9b4364ba22a94c322555b33b6a16222
7490: bug in unique validator
@intel352
thank you for your reply, that is right.
More recent development
Since the extension's main developer has stopped supporting this extension, there has been continued interest, but no real centralized repo for further improvements and bugfixing.
I've forked the original project on GitHub and merged in several outside branches for bugfixes and improvements.
We're currently doing pre-production testing of the extension after these merges, but we may not be using all of its functionnalities. Before releasing a new version, I'd appreciate if some of the users here could take a look.
https://github.com/digitick/yii-mongodb-suite
Checkout the 'release/x.x' or 'develop' branches, as 'master' has not been modified much.
Thank you!
@ianare
I'm glad someone finally took the step towards re-unifying all the forks out there (and even more glad someone fixed the typos in the comments ;) )
What disturbs me a bit about several versions out there (including the one in your fork) is the "optimalisation" to the EMongoDocument::model() function. It's really NOT a good idea IMO to create a new instance of the model every time the function is called. This basically destroys any ability to use scopes (as those rely on the "getDbCriteria" linked to the base model instance and it creates a whole bunch of new objects that really aren't needed.
If you would consider reverting this back to the original implementation then this your version would be really useful to me.
Anyway, keep up the good work! :)
model() reverted
Indeed, this was not optimal. In fact it doesn't work as expected in regards to the Yii AR implementation, which this extension should try to follow.
The branch "release/1.4" has been updated.
Thanks for pointing this out. If you have any more suggestions feel free to open an issue or ask for a pull request.
Facing some issues while configuration... :(
i have configured the extension as it has been showing on the documentation but still im getting error like this.
Property "CDbConnection.mongodb" is not defined. { 211 unset($args[0]); 212 $class=new ReflectionClass($type); 213 // Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+ 214 // $object=$class->newInstanceArgs($args); 215 $object=call_user_func_array(array($class,'newInstance'),$args); 216 } 217 } 218 else 219 $object=new $type; 220 221 foreach($config as $key=>$value) 222 $object->$key=$value; 223 224 return $object; 225 } 226 227 /** 228 * Imports a class or a directory. 229 * 230 * Importing a class is like including the corresponding class file. 231 * The main difference is that importing a class is much lighter because it only 232 * includes the class file when the class is referenced the first time. 233 * 234 * Importing a directory is equivalent to adding a directory into the PHP include path.
my configuration file (main.php) goes like this...
<?php // uncomment the following to define a path alias // Yii::setPathOfAlias('local','path/to/local-folder'); // This is the main Web application configuration. Any writable // CWebApplication properties can be configured here. return array( 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..', 'name'=>'Qoogu', // preloading 'log' component 'preload'=>array('log'), // autoloading model and component classes 'import'=>array( 'application.models.*', 'application.components.*', //mongodb... 'ext.YiiMongoDbSuite.*', ), 'modules'=>array( // uncomment the following to enable the Gii tool 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'admin', // If removed, Gii defaults to localhost only. Edit carefully to taste. 'ipFilters'=>array('127.0.0.1','::1'), // add additional generator path for mongodb 'generatorPaths'=>array( 'ext.YiiMongoDbSuite.gii' ), ), ), // application components 'components'=>array( // uncomment the following to enable URLs in path-format 'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ), ), /*'db'=>array( 'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db', ),*/ // uncomment the following to use a MySQL database /*'db'=>array( 'connectionString' => 'mysql:host=localhost;dbname=slamr', 'emulatePrepare' => true, 'username' => 'root', 'password' => 'root', 'charset' => 'utf8', //'tablePrefix' => 'slm_', ),*/ //mongodb confignuration 'db'=>array( 'mongodb' => array( 'class' => 'EMongoDB', 'connectionString' => 'mongodb://root@127.0.0.1', 'dbName' => 'testdb', 'fsyncFlag' => true, 'safeFlag' => true, 'useCursor' => false ), ), //error handler.. 'errorHandler'=>array( // use 'site/error' action to display errors 'errorAction'=>'site/error', ), //toolbar debugere... 'log'=>array( 'class'=>'CLogRouter', 'routes'=>array( array( 'class'=>'EDMSLogRoute', 'levels'=>'trace, info, error, warning, edms', //add the level edms //Maybe set connectionId and dbName too: see Switching between servers and databases ), ), //deburger toolbar config. 'class'=>'CLogRouter', 'routes'=>array( array( 'class'=>'ext.yii-debug-toolbar.YiiDebugToolbarRoute', 'ipFilters'=>array('127.0.0.1','192.168.1.215'), ), ), ), //'cache' => array('class' => 'system.caching.CDummyCache'), ), // application-level parameters that can be accessed // using Yii::app()->params['paramName'] 'params'=>array( // this is used in contact page 'adminEmail'=>'webmaster@example.com', ), );
Answer http://www.yiiframework.com/extension/yiimongodbsuite/#c9724
Your confignuration here is worng:
//mongodb confignuration 'db'=>array( 'mongodb' => array( 'class' => 'EMongoDB', 'connectionString' => 'mongodb://root@127.0.0.1', 'dbName' => 'testdb', 'fsyncFlag' => true, 'safeFlag' => true, 'useCursor' => false ), ),
Right one
'mongodb' => array( 'class' => 'EMongoDB', 'connectionString' => 'mongodb://root@127.0.0.1', 'dbName' => 'testdb', 'fsyncFlag' => true, 'safeFlag' => true, 'useCursor' => false ),
nop still im getting this error...
nothing problem with my mongodb drivers, coz i had configured directmongosuit extension and was working fine... it created logs for me in db...
my main.php goes like this...
<?php // uncomment the following to define a path alias // Yii::setPathOfAlias('local','path/to/local-folder'); // This is the main Web application configuration. Any writable // CWebApplication properties can be configured here. return array( 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..', 'name'=>'Qoogu', // preloading 'log' component 'preload'=>array('log'), // autoloading model and component classes 'import'=>array( 'application.models.*', 'application.components.*', //mongodb... 'ext.YiiMongoDbSuite.*', ), 'modules'=>array( // uncomment the following to enable the Gii tool 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'admin', // If removed, Gii defaults to localhost only. Edit carefully to taste. 'ipFilters'=>array('127.0.0.1','::1'), // add additional generator path for mongodb 'generatorPaths'=>array( 'ext.YiiMongoDbSuite.gii' ), ), ), // application components 'components'=>array( // uncomment the following to enable URLs in path-format 'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:\w+>/<id:\d+>'=>'<controller>/view', '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>', '<controller:\w+>/<action:\w+>'=>'<controller>/<action>', ), ), 'db'=>array( //'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db', 'connectionString' => 'mongodb://root@127.0.0.1', ), // uncomment the following to use a MySQL database /*'db'=>array( 'connectionString' => 'mysql:host=localhost;dbname=slamr', 'emulatePrepare' => true, 'username' => 'root', 'password' => 'root', 'charset' => 'utf8', //'tablePrefix' => 'slm_', ),*/ //mongodb confignuration 'mongodb' => array( 'class' => 'EMongoDB', 'connectionString' => 'mongodb://127.0.0.1:778', 'dbName' => 'testdb', 'fsyncFlag' => true, 'safeFlag' => true, 'useCursor' => false ), //error handler.. 'errorHandler'=>array( // use 'site/error' action to display errors 'errorAction'=>'site/error', ), //toolbar debugere... 'log'=>array( 'class'=>'CLogRouter', 'routes'=>array( array( 'class'=>'EDMSLogRoute', 'levels'=>'trace, info, error, warning, edms', //add the level edms //Maybe set connectionId and dbName too: see Switching between servers and databases ), ), //deburger toolbar config. 'class'=>'CLogRouter', 'routes'=>array( array( 'class'=>'ext.yii-debug-toolbar.YiiDebugToolbarRoute', 'ipFilters'=>array('127.0.0.1','192.168.1.215'), ), ), ), //'cache' => array('class' => 'system.caching.CDummyCache'), ), // application-level parameters that can be accessed // using Yii::app()->params['paramName'] 'params'=>array( // this is used in contact page 'adminEmail'=>'webmaster@example.com', ), );
In reply to vijaykoogu
@vijaykoogu
db and mongodb are separate components. If you are using mongo db, and not using mysql, remove db component.
mongodb
is not part ofdb
config.Should be like that:
'components' => array( 'mongodb' => array( 'class' => 'EMongoDB', 'connectionString' => 'mongodb://127.0.0.1:778', 'dbName' => 'testdb', 'fsyncFlag' => true, 'safeFlag' => true, 'useCursor' => false ), )
Suite v2 :)
Hey all,
loong 2 yeas have passed since I finished working with Yii and YMDS.
I'm glad to announce that I'm currently working on full re-write of YMDS.
YMDS2 will not be backward compatible with v1.x versions, as some core concepts where changed:
features that poorly tried to implement lack of schema, will be avoided,
if you want to have maximum flexibility, use simple array() Luke
I'll provide ref implementation for embedded document and array
of embedded documents, you can write yours super-extra-featured relation classes.
interface is not guaranteed.
$or
If you want to help, submit some ideas, pull requests - some core concept code
is already on GitHub https://github.com/canni/ymds2
I'll be glad if someone can help with docs(blocks) and proper english speech.
cheers,
canni
Some of my ideas
But first, where you want that ideas to put? gitub issues, or here? Anyway, here's my ideas:
Arbitrary type of embedded, embedded array - I already use it in my fork of ymds, just store _class field for each embed
Gather all and each attribute metada in one place, as there are a lot of options like
It would be great to use annotations for this. I developed yii annotation extension, but unfortunatelly it still requires more docs before I publish it. With annotations defining attributes is plain fun, like that:
/** * @Label('Master pages') * @Versioned * @CollectionName('blah') */ class Page extends EMongoEmbeddedDocument { /** * @Label('Title') * @I18N(allowAny = true) * @RequiredValidator(skipOnError = true) * @var string */ public $title = ''; /** * @EmbeddedArray('PageTemplateRow') * @SafeValidator * @MyOwnAnnotation * @var PageTemplateRow[] */ public $data = [];
$page->title
should return current language title, however in db it is stored as array'title' => [ 'en' => 'Blah', 'pl' => 'Foo' ];
here is my fork of ymds using annotations and above features: https://github.com/Maslosoft/YiiMongoDbSuite
@pmaselkowski
Annotations are great concept, but they require external dependecies and change of Yii users thinking (Yii does not use this anywhere, afaik)
how to compare a string with larger paragraph which is stored in mongoDb?
how to compare a string with larger paragraph which is stored in mongoDb?
i want to select the rows which contain the given string in a field which stores a paragraph.Mine is a search features.Please help...
Migrations?
Hi!
I'm very interested in using this extension. However, I do use some other extensions that rely on migrations to setup some settings. Is there any plan on supporting some type of dummy migration to satisfy those needs? (when you are changing to a system that used to have migrations for example).
Bug in EMongoDocument
EMongoDocument has a bug: it does not use _sort criteria when selecting one object using find method. As a result - wrong object selects.
I fix it for me in this way:
$cursor = $this->getCollection()->find($criteria->getConditions()); if($criteria->getSort() !== null) $cursor->sort($criteria->getSort()); if($criteria->getOffset() !== null) $cursor->skip($criteria->getOffset()); if($criteria->getSelect()) $cursor->fields($criteria->getSelect(true)); $cursor->limit(1); return $this->populateRecord($cursor->getNext());
RE: Igoru-san Migrations?
Migration - it just a command, that can access to DB.
Use Yii::app()->mongodb to access DB, and some collection like "migrations" to check for command execute status. It's same like migrations.
does this extension work ?
PHP warning
include(Mongo.php): failed to open stream: No such file or directory
Re: does this extension work ?
Yes, it work very well. You dont have
php_mongo
extension loaded in yourphp.ini
.yii mongodb listview
I can't use the listview when using this extension;
Can it be used? How?
RE:yii mongodb listview
Use EMongoDocumentDataProvider like any CDataProvider and pass it to list/grid view anything else...
Instantiation problem
Hello,
I have this issue with method instantiate($attributes)
I wanted to make a dynamic attribute model, by single table inheritance
(you can read about it here: http://www.yiiframework.com/wiki/198/single-table-inheritance/).
protected function instantiate($attributes) { if($attributes['type'] === null) { $class = self::DEFAULT_POSITION_CLASS; return new $class; } $class = $attributes['type']; return new $class; }
Tho either I am doing something simply wrong and i'm blind on it, or after the instantiation, my object properties' values are tottaly empty (NULLs), and the funny part is, that the isNewRecord property is false.
Anyone has ever anything common with that ?
Cheers,
F
RE: Instantiation problem
That is because
instantiate
will never set the update scenario (it is not supposed to), onlypopulateRecord
does.RE: RE: Instantiation problem
So what ?
I is populateRecord which invokes instantiate() and sets the scenario to update before it invokes init() and $model->afterFind();
or i still don't get a thing
F
RE: Instantiation problem
You will need to override
populateRecord
with the behaviour you need. This is the function that will be called, or rather should be, called from cursors and what not. I cannot totally remember how YiiMongoDBSuite calls it but I believe it does.RE: RE: Instantiation problem
Sammaye, I honestly do not think it's that way.
My fault with isNewRecord was, cause i created a new $class; and should do new $class()
Unfortunately the records are still not being populated - tho I think they should be, I may check if the afterFind event is fired.
Does your MongoYii extension provide similiar feature, maybe I should look overthere?
Instantiation problem
Right... yes...
$model->initEmbeddedDocuments();
$model->setAttributes($attributes, false);
are in the parent method and I ommited them - I think they should be placed somewhere else.
sorry for bothering
F
Breaking at validation rule
Thanks for awesome extension !
BTW I have a problem, when I write a rule in my generated model as
array('email','unique'),
it gives the following error :
and its behaviors do not have a method or closure named "tableName".
Re: Breaking at validation rule
You don't use the default inbuilt inique validator, you need to use EMongoUniqueValidator
"AND" operator and "NOT LIke"
I'm want to write a query "
SELECT * FROM
page
WHEREkeyphrases
NOT LIKE '%fghjkl%' ANDkeyphrases
LIKE '%abcde%'"
$criteria = new EMongoCriteria;
$criteria->keyphrases('!=', new MongoRegex("/fghjkl/"));
$criteria->addCond('keyphrases','==', new MongoRegex("/abcde/"));
$clients = PageMongo::model()->findAll($criteria);
then I get an error
27017: invalid regular expression operator
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.