2017-09-21 7 views
0

MongoDBコレクションである「products」というSails.jsモデルがあります。モデルでは、 'YYMMDD-count`の形式で' 170921-00001 'のような一意のproductIdを生成するbeforeCreate()フックを持っています。ここで、countはその日に作成されたレコード番号です。私のモデルは次のようになります。Sails.jsのデータベース呼び出しbeforeCreate()モデルフックによって検証エラーが発生する

module.exports = { 

    attributes: { 
     name: { type: 'string', required: true }, 
     productId: { type: 'string', unique: true } 
    }, 


    beforeCreate: function(values, next) { 

     var moment = require('moment'); 

     // Generate the productId 
     Products.count({ 
      createdAt: { 
       '>=': moment().format('YYYY-MM-DD'), 
       '<': moment(moment().format('YYYY-MM-DD')).add(1, 'days').format('YYYY-MM-DD') 
      } 
     }).exec(function(error, productCount) { 

      if (error) { 
       throw error; 
      } 

      var count = '', 
       totalPlaces = 5 - productCount.toString().length; 
      while (totalPlaces > 0) { 
       count = count + '0'; 
       totalPlaces--; 
      } 

      values.productId = moment().format('YYMMDD') + '-' + (count + productCount); 

      next(); 
     }); 
    } 
}; 

1つのデータベースコールで複数の製品をコレクションに挿入しようとすると、この問題が発生します。私は次のエラーを取得する:

debug: Error (E_VALIDATION) :: 1 attribute is invalid 
MongoError: E11000 duplicate key error index: my-app.products.$productId_1 dup key: { : "170921-00002" } 
    at Function.MongoError.create (/Users/Nag/Code/my-app/web-service/node_modules/sails-mongo/node_modules/mongodb-core/lib/error.js:31:11) 
    at toError (/Users/Nag/Code/my-app/web-service/node_modules/sails-mongo/node_modules/mongodb/lib/utils.js:114:22) 
    at /Users/Nag/Code/my-app/web-service/node_modules/sails-mongo/node_modules/mongodb/lib/collection.js:658:23 
    at handleCallback (/Users/Nag/Code/my-app/web-service/node_modules/sails-mongo/node_modules/mongodb/lib/utils.js:95:56) 
    at resultHandler (/Users/Nag/Code/my-app/web-service/node_modules/sails-mongo/node_modules/mongodb/lib/bulk/ordered.js:421:14) 
    at /Users/Nag/Code/my-app/web-service/node_modules/sails-mongo/node_modules/mongodb-core/lib/connection/pool.js:455:18 
    at /Users/Nag/Code/my-app/web-service/node_modules/async-listener/glue.js:188:31 
    at _combinedTickCallback (internal/process/next_tick.js:73:7) 
    at process._tickDomainCallback (internal/process/next_tick.js:128:9) 
    at process.fallback (/Users/Nag/Code/my-app/web-service/node_modules/async-listener/index.js:529:15) 

Invalid attributes sent to undefined: 
• productId 
    • A record with that `productId` already exists (`170921-00002`). 

私は単一のレコードを挿入すると、それが正常に動作しますが、私は複数のレコードを挿入すると、最初のレコードが挿入されますが、後続のすべてのレコードは、そのエラーを生成します。以前のレコードの挿入が完了する前にフックがproductIdを計算する前にドキュメントが挿入されているためですか?これをどうすれば解決できますか?

+0

あなたはどのバージョンのセイルを使用していますか?レコードを作成するために使用しているコードを投稿することはできますか? – sgress454

答えて

0

これはWaterlineで解決するのがかなり難しいものです。このproductIdの規約がまだコードに埋め込まれていない場合は、あまりにも多くのコードを組み立てる前に、それを変更するのが最も賢明です。

は、私は私のコードで同様の問題がありますが、私は、単一の呼び出しでの倍数を作成することはありませんモデルと - 偶然の「衝突」を防ぐために、私はちょうどで作成する前に作成中 try catchを使用して再実行します catchブロック。多くの製品は呼び出しすべてが追加される前に、自分の beforeCreate実行を持って作成した場合でも

var day = new Date(); 
var daycount = 0; 

module.exports = { 

    attributes: { 
     name: { type: 'string', required: true }, 
     productId: { type: 'string', unique: true } 
    }, 
    beforeCreate: function(values, next) { 
     var moment = require('moment'); 
     // Generate the productId 
     Products.count({ 
      createdAt: { 
       '>=': moment().format('YYYY-MM-DD'), 
       '<': moment(moment().format('YYYY-MM-DD')).add(1, 'days').format('YYYY-MM-DD') 
      } 
     }).exec(function(error, productCount) { 
      if (error) { 
       throw error; 
      } 

      // stop here to check your day and count variables... 
      var today = new Date(); 
      if (productCount === 0) { // none created yet today 
       day = today; 
       daycount = 0; 
      } else if (daycount === 0) { // must have started the app with records in db 
       daycount = productCount; 
      } 
      if (day < today && day.getDate() < today.getDate()) { // new day 
       day = today; 
       daycount = 0; 
      } 
      productCount = Math.max(productCount, daycount++); // notice the increment 
      // now proceed as before... 

      var count = '', 
       totalPlaces = 5 - productCount.toString().length; 
      while (totalPlaces > 0) { 
       count = count + '0'; 
       totalPlaces--; 
      } 
      values.productId = moment().format('YYMMDD') + '-' + (count + productCount); 
      next(); 
     }); 
    } 
}; 

:ここ

しかしが、別のソリューションです...多分あなたのProduct.jsファイルでのライブの日カウントを保存することが可能であろう(したがって、同じproductCountを取得する)、daycountおよびday変数は、メモリにライブ状態で保持され、1つずつ更新される必要があります。

でも、この方法をとるのではなく、データを再構築することを真剣に考えています。

0

あなたのAPIにデータを送信するとき、あなたはあなたの製品の名前を確立していますか?

name: { type: 'string', required: true } <= Here, the name is required from client to api. 
+0

あなたの質問はコメントにあるはずです。その質問に対する答えではありません。 –

0

あなたはupdateメソッドの前に一意の値を作成する必要があります。

values.productId = moment().format('YYMMDD') + '-' + (count + productCount);

あなたのこのコード行は次のようになります。

values.productId = moment().format('YYMMDD') + '-' + (count + productCount)+ Math.random();

それは常に一意のIDを生成します。

関連する問題