Uses one query for installation dedup (#2281)

This commit is contained in:
Florent Vilmart
2016-07-19 02:12:29 -04:00
committed by Drew
parent 6f292059ba
commit 4f89ec39cd

View File

@@ -582,65 +582,83 @@ RestWrite.prototype.handleInstallation = function() {
var promise = Promise.resolve(); var promise = Promise.resolve();
var idMatch; // Will be a match on either objectId or installationId var idMatch; // Will be a match on either objectId or installationId
var objectIdMatch;
var installationIdMatch;
var deviceTokenMatches = []; var deviceTokenMatches = [];
// Instead of issuing 3 reads, let's do it with one OR.
let orQueries = [];
if (this.query && this.query.objectId) { if (this.query && this.query.objectId) {
promise = promise.then(() => { orQueries.push({
return this.config.database.find('_Installation', {
objectId: this.query.objectId objectId: this.query.objectId
}, {}).then((results) => { });
if (!results.length) { }
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, if (this.data.installationId) {
orQueries.push({
'installationId': this.data.installationId
});
}
if (this.data.deviceToken) {
orQueries.push({'deviceToken': this.data.deviceToken});
}
if (orQueries.length == 0) {
return;
}
promise = promise.then(() => {
return this.config.database.find('_Installation', {
'$or': orQueries
}, {});
}).then((results) => {
results.forEach((result) => {
if (this.query && this.query.objectId && result.objectId == this.query.objectId) {
objectIdMatch = result;
}
if (result.installationId == this.data.installationId) {
installationIdMatch = result;
}
if (result.deviceToken == this.data.deviceToken) {
deviceTokenMatches.push(result);
}
});
// Sanity checks when running a query
if (this.query && this.query.objectId) {
if (!objectIdMatch) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
'Object not found for update.'); 'Object not found for update.');
} }
idMatch = results[0]; if (this.data.installationId && objectIdMatch.installationId &&
if (this.data.installationId && idMatch.installationId && this.data.installationId !== objectIdMatch.installationId) {
this.data.installationId !== idMatch.installationId) {
throw new Parse.Error(136, throw new Parse.Error(136,
'installationId may not be changed in this ' + 'installationId may not be changed in this ' +
'operation'); 'operation');
} }
if (this.data.deviceToken && idMatch.deviceToken && if (this.data.deviceToken && objectIdMatch.deviceToken &&
this.data.deviceToken !== idMatch.deviceToken && this.data.deviceToken !== objectIdMatch.deviceToken &&
!this.data.installationId && !idMatch.installationId) { !this.data.installationId && !objectIdMatch.installationId) {
throw new Parse.Error(136, throw new Parse.Error(136,
'deviceToken may not be changed in this ' + 'deviceToken may not be changed in this ' +
'operation'); 'operation');
} }
if (this.data.deviceType && this.data.deviceType && if (this.data.deviceType && this.data.deviceType &&
this.data.deviceType !== idMatch.deviceType) { this.data.deviceType !== objectIdMatch.deviceType) {
throw new Parse.Error(136, throw new Parse.Error(136,
'deviceType may not be changed in this ' + 'deviceType may not be changed in this ' +
'operation'); 'operation');
} }
return; }
});
});
}
// Check if we already have installations for the installationId/deviceToken if (this.query && this.query.objectId && objectIdMatch) {
promise = promise.then(() => { idMatch = objectIdMatch;
if (this.data.installationId) {
return this.config.database.find('_Installation', {
'installationId': this.data.installationId
});
} }
return Promise.resolve([]);
}).then((results) => { if (this.data.installationId && installationIdMatch) {
if (results && results.length) { idMatch = installationIdMatch;
// We only take the first match by installationId
idMatch = results[0];
}
if (this.data.deviceToken) {
return this.config.database.find(
'_Installation',
{'deviceToken': this.data.deviceToken});
}
return Promise.resolve([]);
}).then((results) => {
if (results) {
deviceTokenMatches = results;
} }
}).then(() => {
if (!idMatch) { if (!idMatch) {
if (!deviceTokenMatches.length) { if (!deviceTokenMatches.length) {
return; return;