MongoDb + PHP: Cannot specify more than one positional proj. per query - php

I have a "users" collection containing 2 arrays of objects (cards and prizes) each of these 2 can contain data from different companies marked with the "id_company" field.
$list = $users->find(
array(
'cards.id_company' => '... id company ...',
'cards.is_active' => true,
),
array(
'projection' => array(
'_id' => 1,
'full_name' => 1,
'cards.$.id_company' => '...id company...',
'prizes.$.id_company' => '...id company...',
),
'limit' => 5,
)
);
I'm trying to select only the data relating to one company, consequently excluding the others, but I get the following error: Cannot specify more than one positional proj. per query.
Any solutions?

Related

PHP - MongoDB Aggregation: GROUP BY on multi-type field

I have a field in my MongoDB Collection that is hosting two types of data. In some Documents that field has Integer value, e.g.
"campaign_code" : NumberLong(100097)
And in other Documents that field has Array value, e.g.
"campaign_code" : [NumberLong(100087), NumberLong(100136), NumberLong(100137), NumberLong(100138), NumberLong(100135)]
Now, previously I was grouping my result by "campaign_code", but at that time it had only Integer values. Now, the field is having two types of values. The question is is PHP MongoDB driver intelligent to perform the same functionality or do I need to change my code?
My previous PHP code:
$pipeline = array(
array('$match' => array('impression.affiliate_id' => $affiliate_id)),
array(
'$group' => array(
'_id' => array(
'impression.campaign_code' => '$impression.campaign_code'
),
'count' => array('$sum' => 1)
)
),
//sort
array('$sort' => array('count' => -1))
);
I did make some changes and added the following line of code:
array('$unwind' => '$impression.campaign_code')
But this throws an exception:
exception: Value at end of $unwind field path '$impression.campaign_code' must be an Array, but is a NumberLong64
Now the exception is quite valid because few documents have only Integer value in the field. Tell me how I can resolve this issue?

MySQL result multiple arrays

i.e : i have 2 tables
Product ( id, name )
Photo ( id, name, photo_id )
And I need to get result in array like this:
array(
'id' => 1,
'name' => product,
'photos' => array(
array('id' => 1, 'name' => 'photo1')
array('id' => 2, 'name' => 'photo2')
)
}
Is it possible in PHP using clear SQL?
I know that is possible to get 2 arrays and connect it but I have many records and I dont want to wase time to quering.
You have to add a foreign_key in your photo table "product_id".
Then create a method getPhotos() in your Product class with will collect all photos for your product.
Is it possible in PHP using clear SQL?
Not in a single SQL call. With a single call, this is the closest you can get:
array(
'id' => 1,
'name' => product,
'photo_id' => 1,
'photo_name' => 'photo1')
),
array(
'id' => 1,
'name' => product,
'photo_id' => 2,
'photo_name' => 'photo2')
)
Your only choice for the format you want is to run queries separately or to combine them into the data structure you want.
As mentioned, this is not possible with SQL. SQL is based on the relational model which is a 1-Normal-Form data model. That means, the result relation is also flat (no nested relations in a relation).
However, there are good frameworks which generate intermediary models in your corresponding target language (e.g. Python, Java, ...) that circumvent the impression of a flat data model. Check for example Django.
https://docs.djangoproject.com/en/1.8/topics/db/models/
Moo

MongoDB find query with $and $or and $nearSphere in php

After quite some trying out and web research I go crazy with this query. I want to build a query for 'Clubs' around a geo point (distance max 500 meters) in php on MongoDB.
But when I run query it ignores the distance limit and shows all clubs in database BUT sorted by distance.
Here is my dataset (2dsphere index geoLoc):
{"_id":ObjectId("547c649e30afe32c23000048"),"name":"Club Ritzz","category":"Club","category_list":[{"id":"191478144212980","name":"Night Club"}],"location":{"city":"Mannheim"},"geoLoc":{"type":"Point","coordinates":[8.473665839156,49.484065272756]}}
{"_id":ObjectId("547c649f30afe32c2300004a"),"name":"Das Zimmer Mannheim","category":"Club","category_list":[{"id":"191478144212980","name":"Night Club"}],"geoLoc":{"type":"Point","coordinates":[8.4709362941178,49.487260552592]}}
{"_id":ObjectId("547c64ab30afe32c23000063"),"name":"Nationaltheater Mannheim","category":"Arts/entertainment/nightlife","category_list":[{"id":"173883042668223","name":"Theatre"}],"geoLoc":{"type":"Point","coordinates":[8.4776534992592,49.48782606969]}}
{"_id":ObjectId("547c64a130afe32c2300004f"),"name":"SOHO Bar Club Lounge","category":"Club","category_list":[{"id":"191478144212980","name":"Night Club"},{"id":"164049010316507","name":"Gastropub"}],"geoLoc":{"type":"Point","coordinates":[8.4630844501277,49.49385193591]}}
{"_id":ObjectId("547c64a730afe32c2300005a"),"name":"Loft Club","category":"Club","category_list":[{"id":"191478144212980","name":"Night Club"},{"id":"176139629103647","name":"Dance Club"}],"geoLoc":{"type":"Point","coordinates":[8.4296300196465,49.484211928258]}}
And here my php code (updated Dec-2):
$qry = $pub->find(
array( '$and' =>
array(
array( 'geoLoc' =>
array('$nearSphere' =>
array('$geometry' =>
array('type'=>'Point',
'coordinates'=>
array(
floatval($sLon), floatval($sLat)
)
),
'maxDistance' => 500
)
)
),
array( '$or' =>
array(
array( 'name' => new MongoRegex("/.*club/i")),
array( 'name' => new MongoRegex("/.*zimm/i"))
)
),
array('$or' =>
array(
array('category_list.name' => 'Night Club'),
array('category_list.name' => 'Dance Club'),
array('category' => 'Club')
)
)
)
),
array('id' => 1, 'name' => 1, '_id' => 0)
);
Anyone know why the results are not limited to the specified maxDistance?
I found a similar issue on StackOverflow which outlines that one has to use radians for the maxDistance parameter.
See https://dba.stackexchange.com/questions/23869/nearsphere-returns-too-many-data-what-am-i-missing-am-i-wrong-is-it-a-bug-d
Also it is probably helpful if you'd test the query in mongo shell without using the PHP APIs first (just to see if the query is generally working and append '.explain()' to it to see what generally happens inside DB).

Laravel: Get number of occurrences in table

I have this query in Laravel:
Models::select('*')->group_by('user_name')->order_by(DB::raw('count(user_name)'), 'desc')->take(3)->get();
It returns top 3 users by the number they appear in the table.
Q: How can I also get the count parameter(how many times they appear?)
Current response:
array(
"Tim","John","Luke"
);
I need something like this:
array(
array(
"user" => "Tim",
"count" => 3
),
array(
"user" => "John",
"count" => 2
),
array(
"user" => "Luke",
"count" => 1
)
);
Thanks!
You should do the COUNT in the select part of the query and alias it, then use that alias in the ordering.
Something like this, perhaps.
Models::select('*', DB::raw('count(user_name) AS user_count'))->group_by('user_name')->order_by(DB::raw('user_count'), 'desc')->take(3)->get();

cakephp: filtering fields from child table in find('all')

My question extends one posted previously CakePHP: Limit Fields associated with a model. I used this solution effectively for limiting the returned fields for the parent table with this call
$data = $this->SOP10100->find('all',
array('fields' => $this->SOP10100->defaultFields));
However, this method returns the filtered parent and unfiltered child fields. I have 131 child fields of which I only need 7. I have the same defaultFields array construct in the child table. How do I modify this call ( or create a new one) that will return the filtered fields for both parent and child models in the same array?
Here is the structure for the array for the parent table:
public $defaultFields = array(
'SOP10100.SOPNUMBE',
'SOP10100.INVODATE',
'SOP10100.DOCDATE',
'SOP10100.DOCAMNT',
'SOP10100.SUBTOTAL');
Your help is appreciated.
SCORE! Wow, solved two big problems in one day. I finally figured it out with loads of help from many resources:
$this->InvoiceHeader->Behaviors->attach('Containable');
$data = $this->InvoiceHeader->find('all', array(
'fields' => $this->InvoiceHeader->defaultFields,
'contain' => array(
'InvoiceDetail' => array(
'fields' => $this->InvoiceDetail->defaultFields))
)
);
returns my array data just like I want it:
array(
(int) 0 => array(
'InvoiceHeader' => array(
'SOPNUMBE' => 'SVC0202088 ',
'INVODATE' => '2012-04-17 00:00:00',
'DOCDATE' => '2012-04-17 00:00:00',
'DOCAMNT' => '.00000',
'SUBTOTAL' => '.00000'
),
'InvoiceDetail' => array(
(int) 0 => array(
'ITEMNMBR' => 'SERVICE ',
'QUANTITY' => '1.00000',
'UOFM' => 'EA ',
'UNITPRCE' => '.00000',
'TAXAMNT' => '.00000',
'CONTSTARTDTE' => '2012-04-17 00:00:00',
'CONTENDDTE' => '2012-04-30 00:00:00',
'SOPNUMBE' => 'SVC0202088 '
),

Categories