Skip to content

Support for Aggregate Queries #355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 60 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ from your PHP app or script. Designed to work with the self-hosted Parse Server
- [Users](#users)
- [ACLs/Security](#acls)
- [Queries](#queries)
- [Aggregate](#aggregate)
- [Distinct](#distinct)
- [Relative Time](#relative-time)
- [Cloud Functions](#cloud-functions)
- [Cloud Jobs](#cloud-jobs)
Expand All @@ -42,7 +44,7 @@ from your PHP app or script. Designed to work with the self-hosted Parse Server
- [Contributing / Testing](#contributing--testing)

## Installation
There are various ways to install and use this sdk. We'll elaborate on a couple here.
There are various ways to install and use this sdk. We'll elaborate on a couple here.
Note that the Parse PHP SDK requires PHP 5.4 or newer.

### Install with Composer
Expand Down Expand Up @@ -224,7 +226,7 @@ use Parse\ParseAudience;
### Parse Objects

Parse Objects hold your data, can be saved, queried for, serialized and more!
Objects are at the core of this sdk, they allow you to persist your data from php without having to worry about any databasing code.
Objects are at the core of this sdk, they allow you to persist your data from php without having to worry about any databasing code.

```php
$object = ParseObject::create("TestObject");
Expand Down Expand Up @@ -254,7 +256,7 @@ $decodedObject = ParseObject::decode($encoded);

### Users

Users are a special kind of object.
Users are a special kind of object.
This class allows individuals to access your applications with their unique information and allows you to identify them distinctly.
Users may also be linked with 3rd party accounts such as facebook, twitter, etc.

Expand Down Expand Up @@ -302,7 +304,7 @@ $acl->setRoleWriteAccessWithName("PHPFans", true);

### Queries

Queries allow you to recall objects that you've saved to parse-server.
Queries allow you to recall objects that you've saved to parse-server.
Query methods and parameters allow allow a varying degree of querying for objects, from all objects of a class to objects created within a particular date range and more.

```php
Expand All @@ -327,6 +329,59 @@ $first = $query->first();
$query->each(function($obj) {
echo $obj->getObjectId();
});

```
#### Aggregate

Queries can be made using aggregates, allowing you to retrieve objects over a set of input values.
Keep in mind that `_id` does not exist in parse-server. Please replace with `objectId`. MasterKey is Required

For a list of available operators please refer to Mongo Aggregate Documentation.

<a href="https://docs.mongodb.com/v3.2/reference/operator/aggregation/">Mongo 3.2 Aggregate Operators</a>

```php
// group pipeline is similar to distinct, can apply $sum, $avg, $max, $min
// accumulate sum and store in total field
$pipeline = [
'group' => [
'objectId' => null,
'total' => [ '$sum' => '$score']
]
];
$results = $query->aggregate($pipeline);

// project pipeline is similar to keys, add or remove existing fields
// includes name key
$pipeline = [
'project' => [
'name' => 1
]
];
$results = $query->aggregate($pipeline);

// match pipeline is similar to equalTo
// filter out objects with score greater than 15
$pipeline = [
'match' => [
'score' => [ '$gt' => 15 ]
]
];
$results = $query->aggregate($pipeline);
```

#### Distinct

Queries can be made using distinct, allowing you find unique values for a specified field.
Keep in mind that MasterKey is required.
```php
// finds score that are unique
$results = $query->distinct('score');

// can be used with equalTo
$query = new ParseQuery('TestObject');
$query->equalTo('name', 'foo');
$results = $query->distinct('score');
```

#### Relative Time
Expand Down Expand Up @@ -557,7 +612,7 @@ $globalConfigFeatures = ParseServerInfo::getGlobalConfigFeatures();
* "delete" : true
* }
*/

// you can always get all feature data
$data = ParseServerInfo::getFeatures();
```
Expand Down
59 changes: 59 additions & 0 deletions src/Parse/ParseQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,65 @@ public function count($useMasterKey = false)
return $result['count'];
}

/**
* Execute a distinct query and return unique values.
*
* @param string $key field to find distinct values
*
* @return array
*/
public function distinct($key)
{
$sessionToken = null;
if ($user = ParseUser::getCurrentUser()) {
$sessionToken = $user->getSessionToken();
}
$opts = [];
if (!empty($this->where)) {
$opts['where'] = $this->where;
}
$opts['distinct'] = $key;
$queryString = $this->buildQueryString($opts);
$result = ParseClient::_request(
'GET',
'aggregate/'.$this->className.'?'.$queryString,
$sessionToken,
null,
true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked over the PR in detail yet over on the server, but does this require the master key to work? If not we should be adding a method parameter to optionally use the master key, same as how the other query methods work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server requires a masterKey for security purposes

);

return $result['results'];
}

/**
* Execute an aggregate query and returns aggregate results.
*
* @param array $pipeline stages to process query
*
* @return array
*/
public function aggregate($pipeline)
{
$sessionToken = null;
if ($user = ParseUser::getCurrentUser()) {
$sessionToken = $user->getSessionToken();
}
$stages = [];
foreach ($pipeline as $stage => $value) {
$stages[$stage] = json_encode($value);
}
$queryString = $this->buildQueryString($stages);
$result = ParseClient::_request(
'GET',
'aggregate/'.$this->className.'?'.$queryString,
$sessionToken,
null,
true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here regarding the use of the master key. If it's not required to work it should be a method parameter with a default of false.

);

return $result['results'];
}

/**
* Execute a find query and return the results.
*
Expand Down
Loading