-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why afterFind is triggered always before beforeSave? #6088
Comments
It is actually possible to change the response in an afterSave trigger. Take a look in this PR: #5814 |
Thanks for reply! I mean, afterFind alters the input of beforeSave? |
Actually the |
Thanks, @davimacedo! I reviewed the code and yes, It was an issue with my app. There was a method that in beforeSave was searching duplicated data in the same Class. |
Mmm, recently I comment the code in beforeSave: static async beforeSave(request){
super.beforeSave(request);
request.object.unset("sensors");
const query = new Parse.Query(new Device());
const uuid = request.object.get("uuid");
query.equalTo("uuid", uuid);
const result = await query.first({ useMasterKey: true });
if (result && request.object.id !== result.id) throw new Parse.Error(400, JSON.stringify({
uuid: [`${uuid} is already registered.`]
}));
const key = hat();
if (request.object.isNew()) {
request.object.set("key", key);
}
}
static async afterFind(request){
const { objects } = request;
// If no Devices, early return empty array
if (objects.length === 0 ) return [];
const Sensor = Parse.Object.extend("Sensor");
const response = await Promise.all(objects.map(async device => {
const query = new Parse.Query(new Sensor());
query.equalTo("device", device);
return query.find().then(sensors => device.set("sensors", sensors.map( s => s.toJSON())));
}));
return response;
} and this is the trace log: info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "AfterFind"
core-api_1 | Result: "[{\"objectId\":\"0UQiEErAlH\",\"uuid\":\"test\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-27T23:33:44.143Z\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "[{\"uuid\":\"test\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-27T23:33:44.143Z\",\"sensors\":[{\"device\":{\"__type\":\"Pointer\",\"className\":\"Device\",\"objectId\":\"0UQiEErAlH\"},\"name\":\"test\",\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"createdAt\":\"2019-09-24T14:22:27.726Z\",\"updatedAt\":\"2019-09-24T14:22:27.726Z\",\"objectId\":\"xsENQz81sw\"}],\"objectId\":\"0UQiEErAlH\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: beforeSave triggered for Device for user undefined:
core-api_1 | Input: {"uuid":"testing","description":"add","active":true,"createdBy":{"__type":"Pointer","className":"_User","objectId":"m8sGWujfsP"},"key":"ee8bf640246757d3f07f6ad95fcbd09b","connected":false,"createdAt":"2019-09-24T14:22:03.655Z","updatedAt":"2019-09-27T23:33:44.143Z","sensors":[{"device":{"__type":"Pointer","className":"Device","objectId":"0UQiEErAlH"},"name":"test","createdBy":{"__type":"Pointer","className":"_User","objectId":"m8sGWujfsP"},"createdAt":"2019-09-24T14:22:27.726Z","updatedAt":"2019-09-24T14:22:27.726Z","objectId":"xsENQz81sw"}],"objectId":"0UQiEErAlH"}
core-api_1 | Result: {"object":{"uuid":"testing"}} {"className":"Device","triggerType":"beforeSave"} Parse Server version: 3.9.0 |
The |
Take a look at this static async beforeSave(request){
console.log(request.object.toJSON());
// super.beforeSave(request);
// request.object.unset("sensors");
// const query = new Parse.Query(new Device());
// const uuid = request.object.get("uuid");
// query.equalTo("uuid", uuid);
// const result = await query.first({ useMasterKey: true });
// if (result && request.object.id !== result.id) throw new Parse.Error(400, JSON.stringify({
// uuid: [`${uuid} is already registered.`]
// }));
// const key = hat();
// if (request.object.isNew()) {
// request.object.set("key", key);
// }
}
static async afterFind(request){
const { objects } = request;
// If no Devices, early return empty array
if (objects.length === 0 ) return [];
const Sensor = Parse.Object.extend("Sensor");
const response = await Promise.all(objects.map(async device => {
const query = new Parse.Query(new Sensor());
query.equalTo("device", device);
return query.find().then(sensors => device.set("sensors", sensors.map( s => s.toJSON())));
}));
return response;
} logs: core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "AfterFind"
core-api_1 | Result: "[{\"objectId\":\"0UQiEErAlH\",\"uuid\":\"testing\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-27T23:46:48.414Z\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "[{\"uuid\":\"testing\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-27T23:46:48.414Z\",\"sensors\":[{\"device\":{\"__type\":\"Pointer\",\"className\":\"Device\",\"objectId\":\"0UQiEErAlH\"},\"name\":\"test\",\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"createdAt\":\"2019-09-24T14:22:27.726Z\",\"updatedAt\":\"2019-09-24T14:22:27.726Z\",\"objectId\":\"xsENQz81sw\"}],\"objectId\":\"0UQiEErAlH\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | { uuid: 'test',
core-api_1 | description: 'add',
core-api_1 | active: true,
core-api_1 | createdBy:
core-api_1 | { __type: 'Pointer', className: '_User', objectId: 'm8sGWujfsP' },
core-api_1 | key: 'ee8bf640246757d3f07f6ad95fcbd09b',
core-api_1 | connected: false,
core-api_1 | createdAt: '2019-09-24T14:22:03.655Z',
core-api_1 | updatedAt: '2019-09-27T23:46:48.414Z',
core-api_1 | sensors:
core-api_1 | [ { device: [Object],
core-api_1 | name: 'test',
core-api_1 | createdBy: [Object],
core-api_1 | createdAt: '2019-09-24T14:22:27.726Z',
core-api_1 | updatedAt: '2019-09-24T14:22:27.726Z',
core-api_1 | objectId: 'xsENQz81sw' } ],
core-api_1 | objectId: '0UQiEErAlH' }
core-api_1 | info: beforeSave triggered for Device for user undefined:
core-api_1 | Input: {"uuid":"test","description":"add","active":true,"createdBy":{"__type":"Pointer","className":"_User","objectId":"m8sGWujfsP"},"key":"ee8bf640246757d3f07f6ad95fcbd09b","connected":false,"createdAt":"2019-09-24T14:22:03.655Z","updatedAt":"2019-09-27T23:46:48.414Z","sensors":[{"device":{"__type":"Pointer","className":"Device","objectId":"0UQiEErAlH"},"name":"test","createdBy":{"__type":"Pointer","className":"_User","objectId":"m8sGWujfsP"},"createdAt":"2019-09-24T14:22:27.726Z","updatedAt":"2019-09-24T14:22:27.726Z","objectId":"xsENQz81sw"}],"objectId":"0UQiEErAlH"}
core-api_1 | Result: {"object":{"uuid":"test"}} {"className":"Device","triggerType":"beforeSave"} I'm just only editing the object via Parse Dashboard. |
Can you try to do the same using the API Console and send the logs? I am afraid that the Dashboard is performing the find request to retrieve the object data. |
Using the console core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "AfterFind"
core-api_1 | Result: "[{\"objectId\":\"0UQiEErAlH\",\"uuid\":\"test\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-28T00:20:31.269Z\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "[{\"uuid\":\"test\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-28T00:20:31.269Z\",\"sensors\":[{\"device\":{\"__type\":\"Pointer\",\"className\":\"Device\",\"objectId\":\"0UQiEErAlH\"},\"name\":\"test\",\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"createdAt\":\"2019-09-24T14:22:27.726Z\",\"updatedAt\":\"2019-09-24T14:22:27.726Z\",\"objectId\":\"xsENQz81sw\"}],\"objectId\":\"0UQiEErAlH\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: beforeSave triggered for Device for user undefined:
core-api_1 | Input: {"uuid":"test","description":"add","active":true,"createdBy":{"__type":"Pointer","className":"_User","objectId":"m8sGWujfsP"},"key":"ee8bf640246757d3f07f6ad95fcbd09b","connected":false,"createdAt":"2019-09-24T14:22:03.655Z","updatedAt":"2019-09-28T00:20:31.269Z","sensors":[{"device":{"__type":"Pointer","className":"Device","objectId":"0UQiEErAlH"},"name":"test","createdBy":{"__type":"Pointer","className":"_User","objectId":"m8sGWujfsP"},"createdAt":"2019-09-24T14:22:27.726Z","updatedAt":"2019-09-24T14:22:27.726Z","objectId":"xsENQz81sw"}],"objectId":"0UQiEErAlH"}
core-api_1 | Result: {"object":{"uuid":"test"}} {"className":"Device","triggerType":"beforeSave"} |
latest test using the console: static async beforeSave(request){
// console.log(request.object.toJSON());
// super.beforeSave(request);
// request.object.unset("sensors");
// const query = new Parse.Query(new Device());
// const uuid = request.object.get("uuid");
// query.equalTo("uuid", uuid);
// const result = await query.first({ useMasterKey: true });
// if (result && request.object.id !== result.id) throw new Parse.Error(400, JSON.stringify({
// uuid: [`${uuid} is already registered.`]
// }));
// const key = hat();
// if (request.object.isNew()) {
// request.object.set("key", key);
// }
}
static async afterFind(request){
// const { objects } = request;
// // If no Devices, early return empty array
// if (objects.length === 0 ) return [];
// const Sensor = Parse.Object.extend("Sensor");
// const response = await Promise.all(objects.map(async device => {
// const query = new Parse.Query(new Sensor());
// query.equalTo("device", device);
// return query.find().then(sensors => device.set("sensors", sensors.map( s => s.toJSON())));
// }));
// return response;
return [];
} logs: core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "AfterFind"
core-api_1 | Result: "[{\"objectId\":\"0UQiEErAlH\",\"uuid\":\"testing\",\"description\":\"add\",\"active\":true,\"createdBy\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"m8sGWujfsP\"},\"key\":\"ee8bf640246757d3f07f6ad95fcbd09b\",\"connected\":false,\"createdAt\":\"2019-09-24T14:22:03.655Z\",\"updatedAt\":\"2019-09-28T00:35:47.698Z\"}]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: afterFind triggered for Device for user undefined:
core-api_1 | Input: "[]" {"className":"Device","triggerType":"afterFind"}
core-api_1 | info: beforeSave triggered for Device for user undefined:
core-api_1 | Input: {"uuid":"testing","objectId":"0UQiEErAlH"}
core-api_1 | Result: {"object":{"uuid":"testing"}} {"className":"Device","triggerType":"beforeSave"} |
You're right. I've just run the test below and it didn't pass. I will try to understand why.
|
May be, when updating an object parse retrieve the original one. So this could be causing the afterFind trigger. |
There are situations you want to add extra fields to return to the client that alters the request.objects. For instance, when you want to calculate some field in server and then add it to the response.
This "extra field" is passing always to the beforeSave, so this "extra" is pretended to be saved into the object. Currently, I make an unset for the "extra field" in beforeSave and problem solved.
So, my question here is, Why afterFind is triggered before beforeSave? and Is there another way to do this (add extra field to the response)?
Thanks!
The text was updated successfully, but these errors were encountered: