在Parse Server上创建重复条目

时间:2017-10-31 07:30:42

标签: javascript node.js backend parse-server

尝试在循环中创建对象。

myarray=[1,1,1,1,1];

for (var k = 0; k < myarray.length; k++){
      var id = myarray[k];
      aFunctionCreatesParseObjectAndSave(id);
}

在我的aFunctionCreatesParseObjectAndSave(id)函数中,我试图检查是否有一个具有相同id的parse对象。 (用parsequery查看)如果我没有创建,只需更新。但如果没有对象创建它并保存。

function aFunctionCreatesParseObjectAndSave(id){
   var query= new Parse.Query(MyParseObject);
  query.equalTo("myId",id);

  query.first().then(
        function(result){
               if(result === undefined){
                     // there isn't entry for this id
                     //create parseObject and fill it
                     ...
                      newObject.set("id",id);
                      newObject.save();
               }else{
                       // entry found for this id
                       //do update on result and save
                       ...
                       result.save();
                }
         }
   );

}

对于我的测试数组(所有元素都是相同的id),它应该只创建一个条目。但我有myarray.length计数对象:(

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

承诺!

真正简短的回答是你连续五次检查,看看是否有任何东西存在,然后保存第一个对象。

好的,现在回答很久。

你的循环调用aFunctionCreatesParseObjectAndSave。该函数可以实现其功能,但循环并不等待它完成它的工作。对象的查询和保存是异步的,因此函数会立即“返回”,即使它调用的查询继续运行。

希望我能说清楚发生了什么:

  1. 我会对您的代码进行微调,以“证明”正在发生的事情
  2. 我会告诉你如何用诺言善良来做这件事;)。
  3. 最后,如果你想拥有一个唯一的id,请确保在你的后备存储上添加一个唯一的索引(mongo?)。
  4. 这里列出的第一个代码是一个单元测试,其中包含或多或少的代码,以及最后的测试,希望能够显示正在发生的事情....

    // testing boilerplate 2 lines...
    describe('my test', () => {
      it('count', (done) => {
        // ok, this is all "our code"        
        const MyParseObject = 'TestClass';
    
        // a function to count number of records with a given id.
        // Importantly, this function returns a promise.
        const count =  function count(id) {
          return new Parse.Query(MyParseObject)
            .equalTo('myId', id)
            .count(); // <-- count returns a promise
        }
    
         // your function with all the ...'s filled in.
        function aFunctionCreatesParseObjectAndSave(id){
          var query = new Parse.Query(MyParseObject);
          query.equalTo("myId",id);
          query.first().then(
            function(result){
              if(result === undefined){
                // there isn't entry for this id
                //create parseObject and fill it
                const newObject = new Parse.Object(MyParseObject);
                newObject.set('myId',id);
                // you don't wait for this promise to resolve!
                newObject.save();
              } else {
                // entry found for this id
                // do update on result and save
                result.increment('count');
                // this never gets called, and is never waited on...
                result.save();
              }
            });
        }
    
        const myarray = [1,1,1,1,1];
    
        for (var k = 0; k < myarray.length; k++){
          var id = myarray[k];
          aFunctionCreatesParseObjectAndSave(id);
        }
    
        // so what I'm doing here is waiting for 
        // 1 second, then counting the number
        // of records with the same 'myId'.
        // and then testing that each id in the array 
        // got a new object.
        setTimeout(() => {
          count(id)
            // count will be 5 and that's one per element in myarray
            .then(count => expect(count).toBe(myarray.length))
            .then(done)
            .catch(done.fail)
        }, 1000); // 1,000 miliseconds is one second
      });
    });
    

    下面是我如何“修复”代码只创建一个对象,并在每次迭代时递增一个计数器。

    describe('my test', () => {
      const MyParseObject = 'TestClass';
    
      it('count', (done) => {
        // This will call an array of functions that return promises in sequence.
        const sequence = function sequence(tasks) {
          return tasks.reduce((promise, task) => promise.then(() => task.call()), Promise.resolve());
        }
    
        function aFunctionCreatesParseObjectAndSave(id){
          var query = new Parse.Query(MyParseObject);
          query.equalTo("myId",id);
    
          // Very important to return this promise!
          return query.first().then(
            function(result){
              if(result === undefined){
                // there isn't an entry for this id
                //create parseObject and fill it
                const newObject = new Parse.Object(MyParseObject);
                newObject.set('myId', id);
                newObject.set('count', 1);
                // very important to return this promise!
                return newObject.save();
              } else {
                // entry found for this id
                //do update on result and save
                result.increment('count');
                // very important to return this promise!
                return result.save();
              }
            });
        }
    
        const myarray = [1,1,1,1,1];
        const promises = [];
        for (var k = 0; k < myarray.length; k++){
          var id = myarray[k];
          // don't call the function, make an array of functions that call the functions.
          promises.push(() => aFunctionCreatesParseObjectAndSave(id));
        }
    
        // We have an array promises that haven't even started to run.
        // the function sequence() will now execute each promise
        // in the array, then wait till its done and start the next
        // promise.
        sequence(promises)
          .then(() => new Parse.Query(MyParseObject).find())
          .then(results => {
            // this test verifies that there is only one object now.
            expect(results.length).toBe(1);
            const theObj = results[0];
            // the count member of the object should be 5, one for each 
            // id element of 1 in 'myarray'
            expect(theObj.get('count')).toBe(myarray.length);
            done();
          })
          .catch(done.fail);
      });
    });
    

    我在这里做的测试是在nodejs服务器上运行单元测试的上下文中。我写了sequence函数。 “在现实生活中”,特别是如果此代码在浏览器中运行,您需要使用像bluebird这样的库,然后使用mapSeries