How can you specify a max result set for Magento SOAP queries?
I am querying Magento via SOAP API for a list of orders matching a given status. We have some remote hosts who are taking too long to return the list so I'd like to limit the result set however I don't see a parameter for this.
$orderListRaw = $proxy -> call ( $sessionId, 'sales_order.list', array ( array ( 'status' => array ( 'in' => $orderstatusarray ) ) ) );
I was able to see that we do get data back (6 minutes later) and have been able to deal with timeouts, etc. but would prefer to just force a max result set.
It doesn't seem like it can be done using limit, (plus you would have to do some complex pagination logic to get all records, because you would need know the total number of records and the api does not have a method for that) See api call list # http://www.magentocommerce.com/api/soap/sales/salesOrder/sales_order.list.html
But what you could do as a work around is use complex filters, to limit the result set base on creation date. (adjust to ever hour, day or week base on order volume).
Also, since you are using status type (assuming that you are excluding more that just cancel order), you may want to think about getting all order and keep track of the order_id/status locally (only process the ones with the above status) and the remainder that wasn't proceed would be a list of order id that may need your attention later on
Pseudo Code Example
$params = array(array(
'filter' => array(
array(
'key' => 'status',
'value' => array(
'key' => 'in',
'value' => $orderstatusarray,
),
),
),
'complex_filter' => array(
array(
'key' => 'created_at',
'value' => array(
'key' => 'gteq',
'value' => '2012-11-25 12:00:00'
),
),
array(
'key' => 'created_at',
'value' => array(
'key' => 'lteq',
'value' => '2012-11-26 11:59:59'
),
),
)
));
$orderListRaw = $proxy -> call ( $sessionId, 'sales_order.list', $params);
Read more about filtering # http://www.magentocommerce.com/knowledge-base/entry/magento-for-dev-part-8-varien-data-collections
Related
Using MailChimp API V3.0 to create a campaign.
I want to create a campaign that sends to users with a specific interest. It looks like this is possible in the docs, but I've tried every permutation I can think of. I can create the campaign fine as long as I leave out the segment_ops member. Does anyone have an example of PHP code that will do it?
It seems that interests are handled strangely since you don't include the interest-category when setting a users interests via the API. I'm not sure how this affects campaign creation.
I've gotten this to work, API definition can be found here https://us1.api.mailchimp.com/schema/3.0/Segments/Merge/InterestSegment.json
Interests have to be grouped under interest categories (called 'Groups' in some parts of the UI).
Here is the JSON for the segment_opts member of the recipients array:
"segment_opts": {
"match": "any",
"conditions": [{
"condition_type": "Interests",
"field": "interests-31f7aec0ec",
"op": "interestcontains",
"value": ["a9014571b8", "5e824ac953"]
}]
}
Here is the PHP array version with comments. The 'match' member refers to the the rules in the array of 'conditions'. The segment can match any, all, or none of the conditions. This example has only one condition, but others can be added as additional arrays in the 'conditions' array:
$segment_opts = array(
'match' => 'any', // or 'all' or 'none'
'conditions' => array (
array(
'condition_type' => 'Interests', // note capital I
'field' => 'interests-31f7aec0ec', // ID of interest category
// This ID is tricky: it is
// the string "interests-" +
// the ID of interest category
// that you get from MailChimp
// API (31f7aec0ec)
'op' => 'interestcontains', // or interestcontainsall, interestcontainsnone
'value' => array (
'a9014571b8', // ID of interest in that category
'5e824ac953' // ID of another interest in that category
)
)
)
);
You may also send to a Saved segment. The gotcha on this is that the segment_id has to be int. I was saving this value in a db as varchar, and it would not work unless cast to int.
(i am using use \DrewM\MailChimp\MailChimp;)
$segment_id = (int) $methodThatGetsMySegmentID;
$campaign = $MailChimp->post("campaigns", [
'type' => 'regular',
'recipients' => array(
'list_id' => 'abc123yourListID',
'segment_opts' => array(
'saved_segment_id' => $segment_id,
),
),
'settings' => array(
'subject_line' => 'A New Article was Posted',
'from_name' => 'From Name',
'reply_to' => 'info#example.com',
'title' => 'New Article Notification'
)
]);
I have this situation where I could pre-define the array in this way:
$packages = array(
'0' => array(
'name' => 'Hotel1', //pcg name
'curr' => '$',
'amount' => '125',
'period' => 'NIGHT', //pcg duration
'client_data' => array(
'Name' =>'Adrien',
'Addr' =>'Sample Street',
'Payment' =>'Credit Card',
'Nights' =>'6',
)
),
);
Or
$packages = array();
$packages[] = array(
'name' => 'PREMIUM', //pcg name
'curr' => '$',
'amount' => '3.95',
'period' => 'MONTH', //pcg duration
'features' => array(
'Clients' =>'100',
'Invoices' =>'300 <small>MONTH</small>',
'Products' =>'30',
'Staff' =>'1',
)
);
The data will be static always so I wont be fetching this from
a sql query or a dynamic search. Would it make any difference
in terms of performance (the slightest difference could be helpful)
by using the first or the second "method" or they're actually 100%
identical in terms of performance.
Theorically the "dynamic" array creation might be slower because
it needs to check the size of the array, the last array index and
maybe other things such as those.
Thank you.
One simple task like that takes absolutely no resources in current hardware reality. Even in my first PC, a 386DX 20MHz it would not make that difference ;)
Anyway, I executed 1k times both options:
FIRST OPTION average:
0.000114s
SECOND OPTION average:
0.000108s
Be happy!
In ES are filters applied before the query?
Say, for example, I am doing a really slow fuzzy search but I am only doing it on a small date range. For an example you can look below (PHP):
$res=$client->search(array('index' => 'main', 'body' => array(
'query' => array(
'bool' => array(
'should' => array(
array('wildcard' => array('title' => '*123*')),
)
)
),
'filter' => array(
'and' => array(
array('range' => array('created' => array('gte' => date('c',time()-3600), 'lte' => date('c',time()+3600))))
)
),
'sort' => array()
)));
Will the filter be applied before trying that slower search?
Logic would dictate that filters are run and then the query but I would like to be sure.
If you use the filtered-query, then filters will be applied before documents are scored.
This will generally speed things up quite a lot. However, the fuzzy query will still be using the input to build a larger query regardless of the filters.
When you use filter right on the search object, then the query will first run without respecting the filter, then documents will be filtered out of the hits - whereas facets will remain unfiltered.
Therefore, you should almost always use the filtered-query, at least when you are not using facets.
I have a CakePHP model, let's call it Thing which has an associated model called ItemView. ItemView represents one page view of the Thing item. I want to display how many times Thing has been viewed, so I do the following in my view:
<?php echo count($thing['ItemView']); ?>
This works, however as time goes on the result set of this query is going to get huge, as it's currently being returned like so:
array(
'Thing' => array(
'id' => '1',
'thing' => 'something'
),
'ItemView' => array(
(int) 0 => array(
'id' => '1',
'thing_id' => 1,
'created' => '2013-09-21 19:25:39',
'ip_address' => '127.0.0.1'
),
(int) 1 => array(
'id' => '1',
'thing_id' => 1,
'created' => '2013-09-21 19:25:41',
'ip_address' => '127.0.0.1'
),
// etc...
)
)
How can I adapt the model find() to retrieve something like so:
array(
'Thing' => array(
'id' => '1',
'thing' => 'something',
'views' => 2
)
)
without loading the entire ItemView relation into memory?
Thanks!
So it's pretty straight forward, we can make use of countercache - Cake does the counting for you whenever a record is added into/deleted fromItemView:
Nothing to change in your Thing.php model
Add a new INT column views in your things table.
In your ItemView.php model, add counterCache like this:
public $belongsTo = array(
'Thing' => array(
'counterCache' => 'views'
)
);
Then next time when you do addition/deletion via ItemView, Cake will automatically recalculate the counting and cache into views for you, so the next time when you do the query, you also need to make sure you specify recursive = -1 as what #Paco Car has suggested in his answer:
$this->Thing->recursive = -1;
$this->Thing->find(...); //this will returns array of Thing + the field "views"
// --- OR ---
$this->Thing->find(array(
'conditions' => array(
//... your usual conditions here
),
//... fields, order... etc
//this will make sure the recursive applies to this call, once only.
'recursive' => -1
);
The following query returns an array containing the proper ids, but null for all values.
If I remove the aggregation function (AVG()), it returns values (not the averaged ones of course), if I choose e.g. find('all') it returns the average, but not in the list format I want (I could work with that, but I want to try to do it with 'list' first).
$progress = $this->Trial->find('list', array(
'fields' => array(
'Trial.session_id',
'AVG(Trial.first_reaction_time_since_probe_shown) AS average_reaction_time'
),
'group' => 'Trial.session_id',
'conditions' => array(
'Trial.first_valid_response = Trial.probe_on_top',
'TrainingSession.user_id IS NOT NULL'
),
'contain' => array(
'TrainingSession' => array(
'conditions' => array(
'TrainingSession.user_id' => $this->Auth->user('id')
)
)
),
'recursive' => 1,
));
The generated SQL query returns exactly the result I want, when I send it to the DB via PhpMyAdmin.
SELECT
`Trial`.`session_id`,
AVG(`Trial`.`first_reaction_time_since_probe_shown`) AS average_reaction_time
FROM
`zwang`.`trials` AS `Trial`
LEFT JOIN
`zwang`.`training_sessions` AS `TrainingSession` ON (
`Trial`.`session_id` = `TrainingSession`.`id` AND
`TrainingSession`.`user_id` = 1
)
WHERE
`Trial`.`first_valid_response` = `Trial`.`probe_on_top`
GROUP BY
`Trial`.`session_id`
I've examined the source for find('list'). I think it's due to the "array path" for accessing the list getting screwed up when using functions in the query, but I couldn't fix it yet (or recognise my abuse of CakePHP logic).
Once I posted the question, Stackoverflow started relating the correct answers to me.
Apparently, it can't be done with 'list' without virtualFields.
I didn't expect that because it worked using the other find-types.
$this->Trial->virtualFields = array(
'average_reaction_time' => 'AVG(Trial.first_reaction_time_since_probe_shown)'
);
$progress = $this->Trial->find('list', array(
'fields' => array('Trial.session_id','average_reaction_time')
/* etc... */
));