Repository navigation
Querying
Phil edited this page Oct 3, 2026
·
1 revision
Every model on the management API (/api/v2/…) takes the same query methods. Learning Locker serves these models with express-restify-mongoose, so filters are MongoDB queries.
LearningLocker::clients()
->where(['lrs_id' => $storeId]) // query, sent as JSON
->sort(['createdAt' => -1]) // sort, sent as JSON
->select(['_id', 'title', 'scopes']) // only these fields
->populate(['lrs_id']) // expand references
->skip(20)
->limit(10)
->get();| Method | Returns |
|---|---|
get(array $select = []) |
the list, or the document when the resource has an _id
|
first() |
the first match, or null
|
count() |
the number of matches |
create(array $data) |
the created document |
update(array $data) |
the updated document (PATCH) |
delete() |
true |
Each call to the facade starts a fresh resource, so filters never carry over to the next request.
skip() and limit() slow down on big collections. Learning Locker's cursor-based connection API (/api/connection/{model}) doesn't:
$after = null;
do {
$page = LearningLocker::personas()->where(['name' => ['$regex' => '^J']])->paginate(100, $after);
foreach ($page['edges'] as $edge) {
$persona = $edge['node'];
}
$after = $page['pageInfo']['endCursor'];
} while ($page['pageInfo']['hasNextPage']);Run a MongoDB pipeline over the organisation's statements (/api/statements/aggregate):
LearningLocker::aggregate([
['$match' => ['statement.verb.id' => 'http://adlnet.gov/expapi/verbs/completed']],
['$group' => ['_id' => '$statement.object.id', 'count' => ['$sum' => 1]]],
['$sort' => ['count' => -1]],
['$limit' => 10],
], ['maxTimeMS' => 5000]);The options are cache, maxTimeMS and maxScan.
LearningLocker::resource($model, $id = null) reaches any /api/v2 model without a dedicated method, for example Enterprise Journeys:
LearningLocker::resource('journey')->where(['name' => 'Onboarding'])->first();$other = LearningLocker::connect('https://other-lrs.example.com', $key, $secret);
$other->stores()->get();