Skip to content

Commit

Permalink
Add sort and limit options to lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
timothyarmes committed Jun 8, 2020
1 parent 7cfaa91 commit 6de9fe7
Show file tree
Hide file tree
Showing 8 changed files with 2,197 additions and 1,277 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ The `lookup` request accepts a number of fields:
| _foreignField_ | The name of foreign field used by the $lookup
| _preserveIfNull_ (Optional) | Boolean to determine if the parent should should be kept if no join is found (default - `true`)
| _conds_ (Optional) | A *stringified* JSON array of additional conditions used by the lookup
| _sort_ (Optional) | A *stringified* JSON object of sort conditions used by the lookup
| _limit_ (Optional) | Limit the results returned by the lookup (in the even that there is more than one)


Sometimes your lookup will need extra conditions to perform the join between the two collections. Mongo's `$lookup`
command has an advanced feature that allows us to use a sub-pipeline within the primary lookup. Apongo uses this feature to
Expand Down Expand Up @@ -207,6 +210,17 @@ const types = gql`
`;
```

Similarly, `sort` should be a stringified object. Using sort and limit we can simulate a `findOne` when joining one item from another collection.

```
const sortSubTasks = JSON.stringify({ order: -1 }).replace(/"/g, '\\"');
type Task {
_id: String
latestSubTask: SubTask @apongo(lookup: { collection: "subtasks", localField: "_id", foreignField: "taskId", sort: "${sortSubTasks}", limit: 1 })
}
```

### The *compose* request

Apongo also provides a compose request for performing basic string composition between fields:
Expand Down
13 changes: 12 additions & 1 deletion __tests__/apollo-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const taskSchema = new mongoose.Schema({

export const User = mongoose.model('user', userSchema);
export const Task = mongoose.model('task', taskSchema);
export const SubTask = mongoose.model('subtask', taskSchema);

const sortSubTasks = JSON.stringify({ order: -1 }).replace(/"/g, '\\"');

const types = gql`
type User {
Expand All @@ -29,6 +32,12 @@ const types = gql`
_id: String
task: String
user: User @apongo(lookup: { collection: "users", localField: "userId", foreignField: "_id" })
latestSubTask: SubTask @apongo(lookup: { collection: "subtasks", localField: "_id", foreignField: "taskId", sort: "${sortSubTasks}", limit: 1 })
}
type SubTask {
_id: String
order: String
}
type PaginatedTasks {
Expand All @@ -54,14 +63,16 @@ const resolvers = {
...createPipeline('tasks', resolveInfo, context),
{
$facet: {
tasks: [{ $limit: 1 }],
tasks: [{ $limit: 10 }],
count: [
{ $group: { _id: null, count: { $sum: 1 } } },
],
},
},
];

// console.log(JSON.stringify(pipeline, null, 2))

return Task.aggregate(pipeline).exec().then(([{tasks, count}]) => {
return { tasks, count: count.length === 0 ? 0 : count[0].count };
});
Expand Down
22 changes: 15 additions & 7 deletions __tests__/apongo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ const PAGINATED_TASKS = gql`
tasks {
_id
task
user {
_id
name
}
user { _id name }
latestSubTask { _id }
}
}
}
Expand Down Expand Up @@ -61,14 +59,24 @@ afterAll(() => {

describe('lookup', () => {
it('joins top level requests', async () => {
const { data: { tasks } } = await query({ query: TASKS });
const t1 =  tasks.find(({ _id }) => _id === 't1');
const { data: { tasks } } = await query({ query: TASKS });
const t1 = tasks.find(({ _id }) => _id === 't1');
expect(t1.user._id).toEqual("u1")
})

it('joins field level requests', async () => {
const { data: { paginatedTasks } } = await query({ query: PAGINATED_TASKS });
const { data, errors } = await query({ query: PAGINATED_TASKS });
if (errors) console.log(errors);
const { paginatedTasks } = data;
const t1 = paginatedTasks.tasks.find(({ _id }) => _id === 't1');
expect(t1.user._id).toEqual("u1")
})

it('handles advanced lookups', async () => {
const { data, errors } = await query({ query: PAGINATED_TASKS });
if (errors) console.log(errors);
const { paginatedTasks } = data;
const t1 = paginatedTasks.tasks.find(({ _id }) => _id === 't1');
expect(t1.latestSubTask._id).toEqual("st2")
})
});
27 changes: 26 additions & 1 deletion __tests__/test-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default {
"name": "John"
}
],

"tasks": [
{
"_id": "t1",
Expand All @@ -20,5 +21,29 @@ export default {
"userId": "u2",
"task": "fix stuff"
}
]
],

"subtasks": [
{
_id: 'st1',
taskId: 't1',
order: 'a',
},
{
_id: 'st2',
taskId: 't1',
order: 'd',
},
{
_id: 'st3',
taskId: 't1',
order: 'b',
},

{
_id: 'st4',
taskId: 't2',
order: 'a',
},
],
};
Loading

0 comments on commit 6de9fe7

Please sign in to comment.