I'm using parse server + mongodb for back-end and I need help for creating an complexe query:
First here's a schema for my db :
The friends
model represent the friendship between two users.
Each user
has a city
What I'm trying to achieve is to create function that take an userId
as input and return list of cities Sorted by number of friends.
Here's my code until now
function getCities(userId) {
//This query allow to count number of friends in a given city
var innerQuery1 = new Parse.Query(Friends);
innerQuery1. equalTo("user1", userId);
var innerQuery2 = new Parse.Query(Friends);
innerQuery2.equalTo("user2", userId);
countFriendsQueryInCity = Parse.Query.or(innerQuery1, innerQuery2);
countFriendsQueryInCity.equalTo("city", cityId)
countFriendsQueryInCity.count({..})
//This to get all cities
var query = new Parse.Query(City);
query.find({})
}
So the probleme is I can't figure a way way in parse or mongodb to join the two queries ?
Parse doesn't support aggregation queries at this time. Here's an example of how you can do this using the js sdk api. In case you're curious, to make sure that this worked, in my checked out version of the parse-server repo, I created a spec file in the spec directory with all of the below in it then i focused on just the test (by putting an 'f' in front of 'describe').
/**
* Return a sorted list of cities with count of friends in that city
*
* @param userId id of the user to build the list for
* @returns an array of city, count pairs sorted descending
*/
const getCities = function getCities(userId) {
const aggregation = {};
const userPointer = new Parse.Object('Person').set('objectId', userId);
return new Parse.Query('Friend')
.equalTo('user1', userPointer)
.include('user2.city')
.each((friendship) => {
const city = friendship.get('user2').get('city').get('name');
if (aggregation[city]) {
aggregation[city]++
}
else {
aggregation[city] = 1;
}
})
.then(() => {
const sortable = [];
for (const city in aggregation) {
sortable.push([city, aggregation[city]]);
}
return sortable.sort((a, b) => b[1] - a[1]); // desc
});
}
// the unit test for the function above....
fdescribe('play with aggregations', () => {
it('should count friends by city and order desc', (done) => {
// create cities
const ny = new Parse.Object('City').set('name', 'ny');
const sf = new Parse.Object('City').set('name', 'sf');
// create some people to befriend
const people = [
new Parse.Object('Person').set('city', ny),
new Parse.Object('Person').set('city', sf),
new Parse.Object('Person').set('city', sf),
new Parse.Object('Person').set('city', sf),
];
// the object of these friendships
const friendee = new Parse.Object('Person').set('city', sf);
// make the friendships
const friends = people.map(person =>
new Parse.Object('Friend')
.set('user1', friendee)
.set('user2', person));
// just saving the friends will save the friendee and cities too!
Parse.Object.saveAll(friends)
// all saved, now call our function
.then(() => getCities(friendee.id))
.then((result) => {
const lastResult = result.pop();
const firstResult = result.pop();
expect(lastResult[0]).toBe('ny');
expect(lastResult[1]).toBe(1);
expect(firstResult[0]).toBe('sf');
expect(firstResult[1]).toBe(3);
done();
})
.catch(done.fail);
});
});