Mongodb php compound query returns nothing - php

I have the following array:
Array
(
[data.cars] => 44
[data.xp] => Array
(
[$gte] => 100
[$lte] => 500
)
[data.money] => Array
(
[$gte] => 200
[$lte] => 1000
)
)
When issuing this array to find it returns NULL.
Am I doing something wrong, I formated it according to this page, here:
http://us1.php.net/manual/en/mongo.sqltomongo.php
So basically, if I have
SELECT * FROM mytable WHERE data.cars = 44 AND data.xp >= 100 AND data.xp <= 500 AND data.money >= 200 AND data.money <= 1000
This query when run in the console gives exactly 4 results.
Here is the query:
{$and:[{"data.cars":44}, {"data.xp": {$gt:100, $lt:500}}, {"data.money": {$gt:200, $lt:1000}}]}
My array should work, but hey, it does not, please point me to what I'm doing wrong.
Thank you!

The query on MongoDB PHP should be formatted like this:
array(
'data.cars' => 44,
'data.xp' => array(
'$gt' => 100,
'$lt' => 500
),
'data.money' => array(
'$gt' => 200,
'$lt' => 1000
)
)

By doing json_encode() on two version of arrays, both at first sight seem identical, but as you will see, they are not, I discovered the "bug".
Both array's look like so:
array(
'data.cars' => 44,
'data.xp' => array(
'$gt' => 100,
'$lt' => 500
),
'data.money' => array(
'$gt' => 200,
'$lt' => 1000
)
);
One was hardcoded the other was dynamically built, but both json encoded were different, here they are:
{"data.cars":"44","data.xp":{"$gte":"100","$lte":"500"},"data.money":{"$gte":"200","$lte":"1000"}}
{"data.cars":44,"data.xp":{"$gte":100,"$lte":500},"data.money":{"$gte":200,"$lte":1000}}
The first array had the values as string, but couldn't see that on a regular print_r or a var_dump, so what I did was a force cast on the values and ... it WORKED :)
Thank you all guys for your effort and interest!

First of all it is really bad to use . or $ symbols in a keys name (and I actually thought that this is illegal ). This is because dot operator is used to access subdocuments.
So the first thing is to change that. The second thing is that you do not need $and there. So if you want to find the document, which has a = 1 and b = 2, then you do not need to do {$and : .... } all you need to do is {a : 1, b : 2}

Related

Simpliest way to build a multi-dimensional array with SQL result?

I am currently building a web planning and I want to show some data in the period display.
I have a PHP file where I create my SQL request over ~13 tables and fetch all results (I use PDO::FETCH_ASSOC), then I have to loop over my result to build the array I want.
The problem is I need to build a complicated array with lot of data. Here is the kind of result I want to achieve :
$result = array(
$place_1 => array(
'data_place' => array(
'id' => ...,
'name' => ...,
// etc.
),
'data_target' => array(
$target_type_1 => array(
$name_1 => ...,
$name_2 => ...,
// etc.
),
$target_type_2 => array ( ... ),
// etc.
),
'data_isOpen' => array(
$day_1 => array(
$hour_begin => ...,
$hour_end => ...
),
$day_2 => array ( ... ),
// etc.
),
'data_box' => array(
// same kind of stuff with more dimension
)
),
...
$place_n = array(
// same
)
);
When I execute my request, I get something like 3000 array with all the data I need, but I only have 29 places in database so there is a lot of repetition...
$result = array(
0 => array(
"id" => ...,
"name" => ...,
// the list of all fields I need in my big array
),
...
n => array(
// same
)
);
I almost manage to achieve the result I want with some "foreach" and headaches but here is my question :
Is it possible to build a SQL request and fetch the result as I want? I mean, can I group all the result by "id_place" for example but wihtout lost information? And if it's possible, can we do it multiple time?
The idea is to get a result with one array for every place (so 29 and not 3000), then for every "place array", group for example the "hour_begin" and "hour_end" by "opening_day", etc...
Sorry if it's a duplicate, I didn't saw any positive anwser to my question so I try again !

Adding multiple arrays to same key

This seems like a relatively easy thing to do but I'm struggling a bit. Here is a bit of backstory. I'm currently making a schedule of events based off a web service.
Because of the way it outputs data I've been creating and rearranging the information based off the clients wants/needs.
I've created a time array that basically loops through the open hours in 15 min intervals. Example...
Array
(
[0600] => 0
[0615] => 0
[0630] => 0
[0645] => 0
[0700] => 0
[0715] => 0
[0730] => 0
[0745] => 0
[0800] => 0
[0815] => 0
[0830] => 0
[0845] => 0
[0900] => 0
...etc etc
[2300] => 0
)
Once I've done that I loop(using a foreach) through events and if the time is equal to a key add it to the array. The variables are just items from web service.
$timeArray[date('Hi', $roundStart)] = array(
'e_name' => $eventName,
'e_build_id' => $buildId,
'e_start' => $timeStampS,
'e_end' => $timeStampE,
'e_class' => $eClass,
'e_span' => $fullSpan,
'e_status' => $canCheck,
'e_lanes' => $lanesOpen
);
But I've noticed there is a bug with this and that if you have two events at the same time the last one will override the other one. What I need instead is for the events to be within the same key. So adding two or more arrays to the key.
Let me know if this makes sense?
in your initial array, make the values empty arrays:
Array
(
[0600] => []
...etc etc
[2300] => []
)
then when you assign, just push on the array
$timearray[$time][] = $event;
just make sure you always treat the $timearray indexes as arrays, even if they only contain one (or zero!) events.
good luck!
Just make every entry in your interval array an array
// instead the if condition you can initialize the array in your loop when creating it
if (!is_array($timeArray[date('Hi', $roundStart)])) {
$timeArray[date('Hi', $roundStart)] = array();
}
$timeArray[date('Hi', $roundStart)][] = array(
'e_name' => $eventName,
'e_build_id' => $buildId,
'e_start' => $timeStampS,
'e_end' => $timeStampE,
'e_class' => $eClass,
'e_span' => $fullSpan,
'e_status' => $canCheck,
'e_lanes' => $lanesOpen
);
try this:
Array
(
[0600] => array()
...
and
$timeArray[date('Hi', $roundStart)][] = array(
'e_name' => $eventName,
'e_build_id' => $buildId
...
So instead of setting every hour to 0, better set everything to an empty array in your initial run. Instead of checking against 0, you can then check against an array with 0 length. So basically the same. For your date setting loop, you will now, instead of creating a new array, just push to that array. Something like
array_push($timeArray[date('Hi', $roundStart)], array(
'e_name' => $eventName,
'e_build_id' => $buildId,
'e_start' => $timeStampS,
'e_end' => $timeStampE,
'e_class' => $eClass,
'e_span' => $fullSpan,
'e_status' => $canCheck,
'e_lanes' => $lanesOpen
));
should do the job.
After that, just loop over the dates at any given time and execute them all.

POSTing a multidimensional array from Python

I'm trying to POST an array to a RESTful PHP API. The idea is to allow (n>0) records, each containing a remote_id, a dimension_id and a metric.
Here's my client Python:
data = urllib.urlencode([
("remote_id", 1),
("dimension_id", 1),
("metric",metric1),
("remote_id", 1),
("dimension_id", 2),
("metric",metric2)
])
response = urllib2.urlopen(url=url, data=data)
And here's my serverside PHP
<?php
print_r($_POST);
?>
This returns, predictably:
Array
(
[remote_id] => 1
[dimension_id] => 2
[metric] => 16
)
It looks to me like I'm overwriting every instance of remote_id, dimension_id and metric with the final values, which is unsurprising since they're all keyed with identical names.
What's the proper way to do this? I can see a horrible method with unique keys (1_remote_id, 1_dimension_id, 1_metric + 2_remote_id, 2_dimension_id, 2_metric) but that doesn't scale very well.
I guess I'm after something like this PHP, but in Python:
<?php
$observations = array();
$observations[] = [
"remote_id" => "a1",
"metric_id" => "foo",
"metric" => 1
];
$observations[] = [
"remote_id" => "a1",
"metric_id" => "bar",
"metric" => 2
];
?>
Appreciate any tips!
Sam
Don't quote me on this (I haven't done any PHP in a LOOONG time), but this may just work:
data = urllib.urlencode([
("remote_id[]", 1),
("dimension_id[]", 1),
("metric[]",metric1),
("remote_id[]", 1),
("dimension_id[]", 2),
("metric[]",metric2)
])
I would give it a try anyway.

DynamoDB query using search key conditions throwing an odd exception (using PHP)

I'm querying a DynamoDB table using the method described here in the AWS PHP developer guide.
The array that I pass to the Dynamo connection looks like the following:
Array(
[ConsistentRead] => false
[TableName] => bbq_lol_test
[KeyConditions] => Array(
[stinky_cheese] => Array(
[ComparisonOperator] => EQ
[AttributeValueList] => Array(
[S] => camembert)
)
)
)
As you can see, it's in the exact format that the example uses, with the exception of the Type enum (which is just a string).
When executing $connection->query with the above array as an argument, I get the following exception:
Guzzle\Service\Exception\ValidationException:
Validation errors: [KeyConditions][stinky_cheese][AttributeValueList][S][AttributeValue] must be of type object
Which is odd, because the array in the stack trace appears to be fine:
Aws/Common/Client/AbstractClient.php(103): Guzzle\Service\Client->__call("Query", array(array("ConsistentRead" => false, "TableName" => "bbq_lol_test", "KeyConditions" => array("stinky_cheese" => array("ComparisonOperator" => "EQ", "AttributeValueList" => array("S" => "camembert"))))))
I DO have an index on the stinky_cheese field (since I'm using query). I'm probably doing something daft, but I can't seem to figure it out now. Any help would be appreciated - thanks!
There were two problems.
First, AttributeValueList should be an array of arrays, not a single array, going from this:
[AttributeValueList] => Array([S] => camembert)
To this:
[AttributeValueList] => Array(Array([S] => camembert))
Since it's possible to add more stuff in there, like so:
[AttributeValueList] => Array(Array([S] => camembert), Array([S] => bleu))
The second problem was that I always have to query using the primary hash key, which I was not doing.

PHP / Mongo: how do you update nested data?

I've been playing around with Mongo for about a week now and I still can't work out how to modify nested arrays in Mongo with php.
So here is a sample document...
array (
'_id' => new MongoId("4cb30f560107ae9813000000"),
'email' => 'mo#maurice-campobasso.com',
'firstname' => 'Maurice',
'lastname' => 'Campobasso',
'password' => 'GOD',
'productions' =>
array (
0 =>
array (
'title' => 'a',
'date' => '1286811330.899',
),
1 =>
array (
'title' => 'b',
'date' => '1286811341.183',
),
2 =>
array (
'title' => 'c',
'date' => '1286811350.267',
),
3 =>
array (
'title' => 'd',
'date' => '1286811356.05',
),
),
)
What I wan't to do is delete an array inside the productions array, but I can't work out how. I've been playing with 'update('$pull' => ...etc)' but I haven't been able to make it work.
OK, there are a few ways to do this. In your case, I would do something like
mymongoobject.update( $unset : { "productions.2" : 1 } }
That's basically saying to unset the ".2" element of productions. Some docs here.
Now $pull should also work, but it's a little tougher because "productions" is actually an array of arrays (or objects with sub-objects). So you'd have to match arrays exactly:
mymongoobject.update( $pull : { "productions" : {'title':'d', 'date':'1286811356.05'} }
In the case above, the unset is probably the easiest option (though it will leave a "hole" in the array)
That is actually very easy, unlike traditional sql stuff you just modify the whole data and pass it back.
$cursor = $mongo->yourDB->yourCollection->findOne("_id",4cb30f560107ae9813000000);
//let's remove last item on productions
array_splice($cursor["productions"],2);
//and update the mongo document
echo $mongo->yourDB->yourCollection->update($cursor);
//it echoes 1 if successful
hope it helps.

Categories