Skip to content

Commit d80c1e8

Browse files
committed
feat: add support for the $lookup step in $aggregate
1 parent bbe754d commit d80c1e8

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

index.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,24 @@ function extendMemoryDB(MemoryDB) {
7171
};
7272

7373
ShareDBMingo.prototype._querySync = function(snapshots, query, _options) {
74+
var db = this;
7475
if (Array.isArray(query.$aggregate)) {
7576
// sharedb-mongo passes the $aggregate pipeline straight to Mongo, so
7677
// convert Snapshot instances to Mongo doc format for Mingo to operate on.
7778
var mongoDocs = snapshots.map(castToMongoDoc);
78-
var mingoAgg = new Mingo.Aggregator(query.$aggregate);
79+
var aggregatorOptions = {
80+
// support $lookup
81+
collectionResolver: function(collection) {
82+
var collectionDocs = db.docs[collection];
83+
var collectionSnapshots = [];
84+
for (var id in collectionDocs || {}) {
85+
var snapshot = db._getSnapshotSync(collection, id, true);
86+
collectionSnapshots.push(snapshot);
87+
}
88+
return collectionSnapshots.map(castToMongoDoc);
89+
}
90+
};
91+
var mingoAgg = new Mingo.Aggregator(query.$aggregate, aggregatorOptions);
7992
var aggResult = mingoAgg.run(mongoDocs);
8093
return {snapshots: [], extra: aggResult};
8194
}
@@ -121,7 +134,8 @@ function extendMemoryDB(MemoryDB) {
121134
query.hasOwnProperty('$sort') ||
122135
query.hasOwnProperty('$limit') ||
123136
query.hasOwnProperty('$skip') ||
124-
query.hasOwnProperty('$count')
137+
query.hasOwnProperty('$count') ||
138+
query.hasOwnProperty('$aggregate')
125139
);
126140
};
127141

test/query.js

+56
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,62 @@ module.exports = function() {
162162
});
163163
});
164164
});
165+
166+
it('supports $lookup', function(done) {
167+
var users = [
168+
{type: 'json0', id: 'user1', v: 1, data: {name: 'Alice', age: 30}},
169+
{type: 'json0', id: 'user2', v: 1, data: {name: 'Bob', age: 25}}
170+
];
171+
var orders = [
172+
{type: 'json0', id: 'order1', v: 1, data: {userId: 'user1', item: 'Book'}},
173+
{type: 'json0', id: 'order2', v: 1, data: {userId: 'user2', item: 'Pen'}},
174+
{type: 'json0', id: 'order3', v: 1, data: {userId: 'user1', item: 'Notebook'}}
175+
];
176+
var query = {
177+
$aggregate: [
178+
{$lookup: {
179+
from: 'users',
180+
localField: 'userId',
181+
foreignField: '_id',
182+
as: 'userDetails'
183+
}},
184+
{$unwind: '$userDetails'},
185+
{$project: {
186+
_id: 1,
187+
item: 1,
188+
userName: '$userDetails.name',
189+
userAge: '$userDetails.age'
190+
}},
191+
{$sort: {userName: 1, item: 1}}
192+
]
193+
};
194+
195+
var db = this.db;
196+
async.series([
197+
function(cb) {
198+
async.each(users, function(user, innerCb) {
199+
db.commit('users', user.id, {v: 0, create: {}}, user, null, innerCb);
200+
}, cb);
201+
},
202+
function(cb) {
203+
async.each(orders, function(order, innerCb) {
204+
db.commit('orders', order.id, {v: 0, create: {}}, order, null, innerCb);
205+
}, cb);
206+
},
207+
function(cb) {
208+
db.query('orders', query, null, null, function(err, results, extra) {
209+
if (err) return cb(err);
210+
expect(results).eql([]);
211+
expect(extra).eql([
212+
{_id: 'order1', item: 'Book', userName: 'Alice', userAge: 30},
213+
{_id: 'order3', item: 'Notebook', userName: 'Alice', userAge: 30},
214+
{_id: 'order2', item: 'Pen', userName: 'Bob', userAge: 25}
215+
]);
216+
cb();
217+
});
218+
}
219+
], done);
220+
});
165221
});
166222

167223
describe('filtering on special Share properties', function() {

0 commit comments

Comments
 (0)