1

我正在尝试使用CloudCode beforeSave函数将新对象原始对象进行比较。我需要将更新中发送的字段与现有值进行比较。问题是我无法正确获取对象。当我运行查询时,我总是从发送的对象中获取值。

更新:我尝试了一种不同的方法,可以获得旧的寄存器(已经保存在解析中的那个)。但是在请求中发送的新请求被旧请求覆盖。什么?!另一个问题是,即使代码发送了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 );
        }
    );
    }
});

对象发送 {"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 -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"

LOG 日志打印原始值和值,但我也不知道如何访问它。

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
4

5 回答 5

1

经过大量测试和错误后,我可以弄清楚发生了什么。

原来Parse 正在将任何具有相同类和 id 的对象合并到一个实例中。这就是为什么我总是在数据库中注册对象或用户发送的对象。老实说,我无法理解这种行为,但无论如何......

Parse javascript sdk 提供了一种称为Parse.Object.disableSingeInstance 链接的方法 ,可以禁用此“功能”。但是,一旦调用该方法,所有已定义的对象都未定义。这包括发送的对象。女巫意味着您既不能保存发送的对象以供以后参考。

唯一的选择是保存发送的 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 );
        }
    );
  }
});
于 2015-10-06T02:57:15.120 回答
0

您可以通过检查哪些键是脏的来查看修改后的属性,而不是执行查询,这意味着它们已更改但尚未保存。

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 请求。

于 2015-10-02T20:31:08.033 回答
0

如果我是你,我会将旧值作为参数传递给云函数,以便你可以在 request.params.(name of parameter) 下访问它。我不相信有另一种方式来获得旧的价值。一个旧的 SO 问题说您可以使用 .get(),但您声称这不起作用。除非您实际上已经在版本中拥有 9999...

编辑 - 我猜 beforeSave 不像普通函数那样调用......所以创建一个“更新版本”函数,传递当前任务和您尝试更新到的版本,也许?

于 2015-10-02T20:31:19.353 回答
0

嘿,这对我来说非常有用:

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);
        });
于 2016-09-17T08:31:08.390 回答
0

对于那些在 2021 年进入此线程的人,如果您在保存之前在客户端 SDK 中加载了服务器数据,则可以通过context在函数选项中从客户端 SDK 传递该服务器数据save()然后使用它来解决此问题在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()在客户端的函数中加载属性,这对您没有帮助

第二个警告: parse 不会在您的云函数中为您处理(取消)序列化,例如:

{
  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
    }
  }
}
于 2021-04-14T19:09:06.780 回答