如何在保存之前查询 CloudCode 中的对象?
Posted
技术标签:
【中文标题】如何在保存之前查询 CloudCode 中的对象?【英文标题】:How to query objects in the CloudCode beforeSave? 【发布时间】:2015-10-02 20:00:11 【问题描述】:我正在尝试使用 CloudCode beforeSave 函数将 新对象 与 原始 进行比较。我需要将 update 中发送的字段与现有值进行比较。问题是我无法正确获取对象。当我运行查询时,我总是从发送的对象中获取值。
更新:我尝试了一种不同的方法,并且可以获得旧的寄存器(已经保存在解析中的那个)。 但是在请求中发送的新请求被旧请求覆盖。什么?!另一个问题是,即使代码发送了response.success()
,更新也没有保存。
我认为我在这里遗漏了一些非常明显的东西。或者我正面临一个错误或什么...
新方法
Parse.Cloud.beforeSave('Tasks', function(request, response)
if ( !request.object.isNew() )
var Task = Parse.Object.extend("Tasks");
var newTask = request.object;
var oldTask = new Task();
oldTask.set("objectId", request.object.id);
oldTask.fetch()
.then( function( oldTask )
console.log(">>>>>> Old Task: " + oldTask.get("name") + " version: " + oldTask.get("version"));
console.log("<<<<<< New Task: " + newTask.get("name") + " version: " + newTask.get("version"));
response.success();
, function( error )
response.error( error.message );
);
);
OBJ 发送 "name":"LLL", "version":333
日志
I2015-10-02T22:04:07.778Z]v175 before_save triggered for Tasks for user tAQf1nCWuz:
Input: "original":"createdAt":"2015-10-02T17:47:34.143Z","name":"GGG","objectId":"VlJdk34b2A","updatedAt":"2015-10-02T21:57:37.765Z","version":111,"update":"name":"LLL","version":333
Result: Update changed to
I2015-10-02T22:04:07.969Z]>>>>>> Old Task: GGG version: 111
I2015-10-02T22:04:07.970Z]<<<<<< New Task: GGG version: 111
注意:我正在通过 cURL 和解析控制台测试登录。
CloudCode beforeSave
Parse.Cloud.beforeSave("Tasks", function( request, response)
var query = new Parse.Query("Tasks");
query.get(request.object.id)
.then(function (oldObj)
console.log("-------- OLD Task: " + oldObj.get("name") + " v: " + oldObj.get("version"));
console.log("-------- NEW Task: " + request.object.get("name") + " v: " + request.object.get("version"));
).then(function ()
response.success();
, function ( error)
response.error(error.message);
);
);
cURL 请求
curl -X PUT \
-H "Content-Type: application/json" \
-H "X-Parse-Application-Id: xxxxx" \
-H "X-Parse-REST-API-Key: xxxxx" \
-H "X-Parse-Session-Token: xxxx" \
-d "\"name\":\"NEW_VALUE\", \"version\":9999" \
https://api.parse.com/1/classes/Tasks/VlJdk34b2A
JSON 响应
"updatedAt": "2015-10-02T19:45:47.104Z"
记录 日志打印 original 和 new 值,但我也不知道如何访问它。
I2015-10-02T19:57:08.603Z]v160 before_save triggered for Tasks for user tAQf1nCWuz:
Input: "original":"createdAt":"2015-10-02T17:47:34.143Z","name":"OLD_VALUE","objectId":"VlJdk34b2A","updatedAt":"2015-10-02T19:45:47.104Z","version":0,"update":"name":"NEW_VALUE","version":9999
Result: Update changed to "name":"NEW_VALUE","version":9999
I2015-10-02T19:57:08.901Z]-------- OLD Task: NEW_VALUE v: 9999
I2015-10-02T19:57:08.902Z]-------- NEW Task: NEW_VALUE v: 9999
【问题讨论】:
我不确定你能做到这一点。你这样做的目的是什么?也许我们可以找到不同的解决方案。 我需要检查寄存器的版本,并与请求中发送的版本进行比较。 这很奇怪,我真的不明白为什么你的标有“新方法”的版本不起作用......它应该。我看到您关于 Parse.Object.disableSingeInstance 的注释,但这是我第一次听说。似乎这非常低效,因为您必须两次获取对象。我会通过 Twitter 或 FB 联系 Hector 并询问此事。 @MobileVet 我完全同意你的看法。在生产场景中,我的解决方案是不可取的。事实上,这个问题太疯狂了,我正在考虑完全放弃 Parse。如果这个 Hector 是 Parse.com 的人,你能给我他的联系方式吗?也许他能把我从这个地狱里救出来。 @MobileVet 我已经有了他的联系方式。 Tks 给小费。现在会尝试联系他 【参考方案1】:经过大量测试和错误,我可以弄清楚发生了什么。
事实证明 Parse 正在将任何具有相同类和 id 的对象合并到一个实例中。这就是为什么我总是在数据库中注册对象或用户发送的对象。老实说,我无法理解这种行为,但无论如何......
Parse javascript sdk 提供了一种名为 Parse.Object.disableSingeInstance
link 的方法,该方法禁用了此“功能”。但是,一旦调用该方法,所有已定义的对象都未定义。这包括发送的对象。女巫的意思是,您既不能保存发送的对象以供以后参考。
唯一的选择是保存发送的 obj 的键和值并在以后重新创建它。因此,我需要在调用 disableSingleInstance
之前捕获请求,将其转换为 JSON,然后禁用单个实例,获取保存在 DB 中的对象并使用保存的 JSON 重新创建发送的对象。
它不漂亮,绝对不是最有效的代码,但我找不到任何其他方式。如果有人有另一种方法,一定要告诉我。
Parse.Cloud.beforeSave('Tasks', function(request, response)
if ( !request.object.isNew() )
var id = request.object.id;
var jsonReq;
var Task = Parse.Object.extend("Tasks");
var newTask = new Task;
var oldTask = new Task;
// getting new Obj
var queryNewTask = new Parse.Query(Task);
queryNewTask.get(id)
.then(function (result)
newTask = result;
// Saving values as a JSON to later reference
jsonReq = result.toJSON();
// Disable the merge of obj w/same class and id
// It will also undefine all Parse objects,
// including the one sent in the request
Parse.Object.disableSingleInstance();
// getting object saved in DB
oldTask.set("objectId", id);
return oldTask.fetch();
).then(function (result)
oldTask = result;
// Recreating new Task sent
for ( key in jsonReq )
newTask.set( key, jsonReq[key]);
// Do your job here
, function (error)
response.error( error.message );
);
);
【讨论】:
【参考方案2】:如果我是你,我会将旧值作为参数传递给云函数,以便你可以在 request.params.(参数名称)下访问它。我不相信有另一种方式来获得旧的价值。一个古老的 SO 问题说您可以使用 .get(),但您声称这不起作用。除非您实际上已经在版本中拥有 9999...
edit - 我猜 beforeSave 不像普通函数那样被调用......所以创建一个“更新版本”函数来传递当前任务和您尝试更新到的版本,也许?
【讨论】:
我做不到。当我说 OLD 时,我指的是保存在数据库中的寄存器。我需要比较新的寄存器 Parse 不允许您将参数传递给beforeSave
挂钩。来源:parse.com/questions/how-to-access-request-params-in-beforesave
@Russell 查看我所做的编辑。 TinMegali ,您必须将当前值和您尝试更改的新值传递给单独的函数,进行比较,然后在满足您的要求时保存。【参考方案3】:
您可以通过检查哪些键是脏来查看修改后的属性,而不是执行查询,这意味着它们已更改但尚未保存。
JS SDK 包含dirtyKeys()
,它返回已更改的密钥。试试这个。
var attributes = request.object.attributes;
var changedAttributes = new Array();
for(var attribute in attributes)
if(object.dirty(attribute))
changedAttributes.push(attribute);
// object.get(attribute) is changed and the key is pushed to the array
为了澄清,要获取原始属性的值,您必须调用get()
来加载这些预保存值。需要注意的是,这将被视为另一个 API 请求。
【讨论】:
根据博客的dirtyKey解析比较有用,字段被修改了对吧?但我需要特定字段的值。我需要将注册的字段值与请求中的相同字段值进行比较。有办法用dirtyKey做到这一点吗? 刚刚更新了我的帖子以澄清。您是正确的,dirtyKey
只能用于告知哪些属性已更改,但 不能 事先告知键的值。这些必须使用另一个请求来获取。 Parse 不会在 JS SDK 中暴露 previousAttributes()
或 previous("columnName")
。
对,但这是我的问题。当我尝试在 beforeSave 函数中获取存储在数据库中的值时,我收到的是用户发送的值,而不是解析中保存的值。假设 X 类存储了一个值 100,用户发送了 900。当我尝试获取 X 类时,使用用户发送的 objId 我得到了 900。用户发送的值完全相同?查看我在问题中的查询。
我认为问题在于查询是异步执行的。到查询承诺完成时,修改后的对象已经被保存。将您的response.success()
移动到两个日志记录语句下方。通过调用 response.success(),您表示对象保存可以继续进行
据我了解,“响应”在另一个承诺中被调用,因此,仅在控制台打印后触发。对?我对承诺的事情很陌生,但它看起来对我来说是正确的。看看代码,如果我错了,请纠正我。 Tks =)【参考方案4】:
嘿,这对我来说非常有用:
var dirtyKeys = request.object.dirtyKeys();
var query = new Parse.Query("Question");
var clonedData = null;
query.equalTo("objectId", request.object.id);
query.find().then(function(data)
var clonedPatch = request.object.toJSON();
clonedData = data[0];
clonedData = clonedData.toJSON();
console.log("this is the data : ", clonedData, clonedPatch, dirtyKeys);
response.success();
).then(null, function(err)
console.log("the error is : ", err);
);
【讨论】:
【参考方案5】:对于那些在 2021 年进入此线程的人,如果您在保存之前已在客户端 SDK 中加载了服务器数据,您可以通过从客户端 SDK 传递该服务器数据来解决此问题在save()
函数的context
选项中,然后在beforeSave
afterSave
云函数中使用它。
// eg JS client sdk
const options =
context:
before: doc._getServerData() // object data, as loaded
doc.save(null, options)
// #beforeSave cloud fn
Parse.Cloud.beforeSave(className, async (request) =>
const before = request.context
// ... do something with before ...
)
警告:如果您没有在客户端的 _getServerData()
函数中加载属性,这对您没有帮助
第二个警告:解析不会在您的云函数中为您处理(取消)序列化,例如:
before: // < posted as context
status:
is: 'atRisk',
comment: 'Its all good now!',
at: '2021-04-09T15:39:04.907Z', // string
by: [Object] // pojo
,
after:
status: // < posted as doc's save data
is: 'atRisk',
comment: 'Its all good now!',
at: 2021-04-09T15:39:04.907Z, // instanceOf Date
by: [ParseUser] // instanceOf ParseUser
【讨论】:
以上是关于如何在保存之前查询 CloudCode 中的对象?的主要内容,如果未能解决你的问题,请参考以下文章