How to duplicate and EmbeddedDocument in Doctrine (with MongoDb) - mongodb

In in Doctrine ODM 1.0beta3, I need to take an #EmbeddedDocument from a Document, and to put it in another Document.
However when I try to do this, I get strange results.
There is a way to duplicate and EmbeddedObject?
EDIT:
The "strange" result is that a property of this embedded document is inserted alongside the other embedded documents.
More details:
I have a Queue embedded document with several Job documents in an #EmbedMany relationship:
Queue: -> [ Job, Job, Job]
Also some Jobs have another Job in a #EmbedOne property called $callback:
class Job {
/** #EmbedOne(targetDocument="Cron\Model\Document\Job") */
private $callback;
/** #Hash */
private $result;
}
/*
* #EmbeddedDocument
*/
class Queue {
/** #EmbedMany(targetDocument="Cron\Model\Document\Job") */
private $jobs = array();
//Getters and setters...
}
What I'm trying to do is to get the $callback Job, add a value to the $result hash and to enqueue this Job in the $jobs array().
What I get is the Job enqueued, but also the $result hash in the $jobs array, as if it was a Job document.
jobs array from mongodb:
...
[2] => Array
(
[parameters] => Array
(
[field] => office
[result] => "foo"
)
)
[3] => Array
(
[_id] => 638
[parameters] => Array
(
[field] => office
[result] => "foo"
)
)
The code is this:
$job = $queue->getLastJob();
$callback = $job->getCallback();
$params = $callback->getParameters();
$params['result'] = 'foo';
$callback->setParameters($params);
$queue->addJobs($callback);

I think you would tackle this problem as you would in any other language.
Just copy the object:
$some_obj["embedded_document"] = $other_obj["embedded_document"];
My understanding is that php makes a copy of the object instead of a reference and I've confirmed it locally.
What strange results are you getting exactly? If you provide some more information I can try to help.
Cheers!

Related

Integration tests with mongodb

I'm using mongodb as my main database, so on my integration tests I try to test if my system handles the data as expected. The process is as follow:
Insert data on needed collections to prepare scenario
Perform call to the system
Validate data change or exist on database, depending of the scenario
I'm using behat as my BDD testing tool and I implement on my FeatureContext to insert and read data from collections, something like this:
Given I have the following data on collection Brand
[
{
"_id": "575df0b00419c905492d0461",
"name": "Adidas",
"image": "adidas.png"
}
]
Then I validate the following data exists on collection Brand
[
{
"_id": "575df0b00419c905492d0461",
"name": "Adidas",
"image": "adidas.png"
}
]
EDIT
/**
* #Given I have the following data on collection :collectionName
* #param string $collectionName
* #param PyStringNode $collectionData
* #throws Exception
*/
public function iHaveTheFollowingDataOnCollection($collectionName, PyStringNode $collectionData)
{
$data = json_decode($collectionData->getRaw(), true);
foreach ($data as $index => $element) {
foreach ($element as $key => $value) {
if ($key === '_id') {
$data[$index][$key] = new \MongoDB\BSON\ObjectID($value);
}
if (strpos($key, "#") !== false) {
$key = explode("#", $key)[1];
$data[$index][$key] = array(
"\$ref" => $value["\$ref"],
"\$id" => new \MongoDB\BSON\ObjectID($value["\$id"]),
"\$db" => $value["\$db"],
);
}
if ($value === "UNIX_TIME()") {
$data[$index][$key] = time();
}
}
}
$collection = $this->db->$collectionName;
foreach ($data as $document) {
$collection->insertOne($document);
}
}
END EDIT
The issue is that I have at least 1k different scenarios on different features and with that heavy usage test randomly fails becase it don't find expected data on collection.
My first thought is that exist some delay on insertion and availability of the data.
Any thoughts and how to fix it?

DBIx::Class: sub resultset in Template Toolkit presented as an array, not a resultset

I am developing a Catalyst application using DBIx::Class and Template Toolkit; in the particular part I'm having issues with, I have a resultset obtained using by calling the following function in my ResultSet schema:
sub divisions_and_teams_in_season {
my ( $self, $season, $grid ) = #_;
return $self->search({
"division_seasons.season" => $season->id,
"division_seasons.fixtures_grid" => $grid->id,
}, {
prefetch => [
"division_seasons",
{
"team_seasons" => {
"team" => [{
"club" => "venue"
},
"home_night"
]
}
}
],
order_by => {
-asc => [ qw( division_seasons.rank team_seasons.grid_position club.short_name team.name ) ]
}
});
}
This returns the data as I would expect and I'm able to do the following in my Controller code to get back my resultset and iterate through the team_seasons:
my $divisions = [ $c->model("DB::Division")->divisions_and_teams_in_season($current_season, $c->stash->{grid}) ];
foreach my $division ( #{ $divisions } ) {
$c->log->debug( $division->team_seasons->grid_positions_filled ); # This works because $division->team_seasons is a resultset object
}
However, in my template (having stashed $divisions), I'm unable to access the grid_positions_filled object because division.team_seaons gives me an arrayref of team resultsets in that division:
[%
# Loop through our divisions
FOREACH division IN divisions;
CALL c.log.debug(division.team_seasons); # The output of this is something like: ARRAY(0x6f8318c)
END;
-%]
The output I get for the same debug log in my controller is more like a list of resultset objects:
TopTable::Model::DB::TeamSeason=HASH(0x6eea94c)
TopTable::Model::DB::TeamSeason=HASH(0x6f01834)
TopTable::Model::DB::TeamSeason=HASH(0x6ef5284)
TopTable::Model::DB::TeamSeason=HASH(0x6efec9c)
TopTable::Model::DB::TeamSeason=HASH(0x6ef4dc4)
TopTable::Model::DB::TeamSeason=HASH(0x6faf0ac)
TopTable::Model::DB::TeamSeason=HASH(0x6eefa04)
Hope all this makes sense! Does anyone know how I can get the behaviour from the controller into the template so that I can access methods on the team_season ResultSet?
Thank you very much in advance.
Try $self->search_rs rather than $self->search. "This method does the same exact thing as search() except it will always return a resultset, even in list context."
See the docs for more info.
The team_seasons accessor returns a resultset in scalar context, and an array of rows in list context. It seems that template toolkit code evaluates the accessor in list context.
As a work-around, DBIC installs a special accessor, postfixed with _rs that always returns a resultset regardless of context. So the following should work:
CALL c.log.debug(division.team_seasons_rs.grid_positions_filled);
This is documented under DBIx::Class::Relationship.

Array display issue

I have a database table ("buildings") in MySQL consisting of 3 columns:
Name
Place
Number
I have created a dropdown list in my view page which contains the names of the buildings and also a textarea.
Now, depending on which name the user selects, the textarea should be populated with the respective place and number of the name of the building. I’m able to get the result but I want the output to be more readable. Right now, the format of the output is as:
Array
(
[0] => Array
(
[Number] => 14
[Place] => Cambodia
)
)
Is there anyway I could get the output to be as simple as:
Number : 14
Place: Cambodia
Her's the model code:
<?php
class Application_Model_Building extends Zend_Db_Table_Abstract
{
public function getname($name)
{
$db = $this->getDefaultAdapter();
$auth = Zend_Auth::getInstance();
$select = "SELECT * FROM buildings where name = $name";
$stmt = $db->query($select);
$result = $stmt->fetchAll();
print_r ($result);
}
}
?>
instead of echoing the array dump, try:
foreach ($result as $vals) {
echo "Place: ".$vals["Place"]."<br>Number: ".$vals["Number"];
}
as other posters have commented, you should read about php arrays so you know why this makes sense

How do i pass a variable for the query in a get Manager call?

I am trying to make a simple Rose DB call:
$id = xyz;
$name = "company";
DataB::testTable::Manager->get_testTable( query =>[ id => $id, name => $name ] );
in it possible to not have the whole query written every time, and declare it like a string variable such that i can just call
DataB::testTable::Manager->get_testTable( query =>[ $query ] );
where $query = qq { id => $id , name => $name };
Please Help
By what I understood from your question, I am giving this answer.
Try this one.
my $myquery = {query =>{ id=>$id, name=>$name }} ;
TGI::testTable::Manager->get_testTable($myquery);
Hope, this gives some idea to you.
Edit for "Hash with Array reference":
my $myquery = [ id=>$id, name=>$name ] ;
TGI::testTable::Manager->get_testTable(query => $myquery);
check out this : How to pass a a string variable as "query" for get Manager call?
Well actually i figured out how to do that . Its not that complicated. Only thing is RoseDB objects expect an array reference for a query. So something like this works :
my #query = ( id => $id, name => $name );
testDB::testTable::Manager->get_testTable( query => \#query );
Just thought would answer it myself, incase someonelse is looking for a solution to this

Rose::DB::Object::Manager query with a list of object ids

I'm trying to write a Rose::DB::Object query string using either an Array or a Hash, however I'm unsure how to do it. I'm trying to write an update function based off of certain ID's in a list that are enumerated in the array. I unfortunately do not have any other unique key to filter on to build the query, so I need to query specific ID's.
Essentially I am trying to programatically write the follow:
my $list = My::DB::Manager->get_items(query => [
{id => 1},
{id => 14},
{id => 210},
{id => 1102},
{id => 3151},
]);
This is the code I have so far, but I haven't been able to successfully achieve what I am trying to do:
use My::DB::Manager;
my #ary;
foreach (#_) {
my %col = ("id", $_);
push (#ary, \%col);
}
my $list = My::DB::Manager->get_items(query => \#ary);
...
./test.pl
Now the script just hangs with no output indefinately.
I'm trying to avoid iterating through the DB::Manager and making a DB call on a per record basis as this script will be run via cron every 60 seconds and has the potential to return large sets.
The query parameter takes a reference to an array of name/value pairs, not a reference to an array of hash references. If you want objects where the value of the id column is one of a list of values, then use the name id and a reference to an array of ids as the value. This code should work (assuming the id values are in #_):
$list = My::DB::Manager->get_items(query => [ id => \#_ ]);
You push strings into #ary when you need to push perl structures:
use My::DB::Manager;
my #ary;
foreach (#_) {
push (#ary, { id => $_ });
}
my $list = My::DB::Manager->get_items(query => [#ary]);
...
However, I think you can use query => [ id => [$id1, $id2, ... ], ...]:
use My::DB::Manager;
my $list = My::DB::Manager->get_items(query => [ id => \#_ ]);
...
Never used Rose, this based on docs of the module.