簡體   English   中英

如何編寫Sails.js模型,以便不會為每個新文檔都重新創建關聯的類別?

[英]How do I write my Sails.js model so that associated categories aren't recreated for every new document?

我覺得必須有一個簡單的解決方案,但是我似乎找不到正確的在線搜索方法。 我在Node.js和Express上使用Sails服務器。 現在,我正在嘗試使基本的CRUD API正常運行,因此我一直在發送post並獲取與Postman的連接。

我從一個空數據庫(托管在Mongolab上)開始,嘗試創建兩個名稱不同但類別相同的文檔。 之后,我希望類別集合中只有1個文檔,而主要集合中只有2個文檔。 相反,第二個POST會觸發一個錯誤,因為盡管具有{unique:true}屬性,它仍試圖創建第二個類別文檔。

我該怎么做才能解決此錯誤並擁有正確的一對多關系?

\\ API \\型號\\ Beer.js:

module.exports = {
  attributes: {
    // Primitive attributes
    name: {
      type: 'string',
      required: true,
      unique: true
    },
    alcoholByVolume: {
      type: 'float',
      defaultsTo: null
    },
    beerAdvocateId: {
      type: 'integer',
      defaultsTo: null
    },

    // Associations (aka relational attributes)
    brewery: { model: 'Company' },
    style: { model: 'BeerStyle' }
  }
};

\\ API \\型號\\ Company.js:

module.exports = {
  attributes: {
    name: {
      type: 'string',
      required: true,
      unique: true
    },
    countryCode: {
      type: 'string',
      enum: ['ad', 'ae', 'af', 'ag', 'ai', 'al', 'am', 'ao', 'aq', 'ar', 'as', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'bj', 'bl', 'bm', 'bn', 'bo', 'bq', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'cr', 'cu', 'cv', 'cw', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'ee', 'eg', 'eh', 'er', 'es', 'et', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mf', 'mg', 'mh', 'mk', 'ml', 'mm', 'mn', 'mo', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'nc', 'ne', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'ss', 'st', 'sv', 'sx', 'sy', 'sz', 'tc', 'td', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tr', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'za', 'zm', 'zw'],
      defaultsTo: 'us'
    }
  }
};

\\ API \\型號\\ BeerStyle.js:

module.exports = {
  attributes: {
    name: {
      type: 'string',
      enum: ['American Amber / Red Ale', 'American Barleywine', 'American Black Ale', 'American Blonde Ale', 'American Brown Ale', 'American Dark Wheat Ale', 'American Double / Imperial IPA', 'American Double / Imperial Stout', 'American IPA', 'American Pale Ale (APA)', 'American Pale Wheat Ale', 'American Porter', 'American Stout', 'American Strong Ale', 'American Wild Ale', 'Black & Tan', 'Chile Beer', 'Cream Ale', 'Pumpkin Ale', 'Rye Beer', 'Wheatwine', 'Belgian Dark Ale', 'Belgian IPA', 'Belgian Pale Ale', 'Belgian Strong Dark Ale', 'Belgian Strong Pale Ale', 'Bière de Champagne / Bière Brut', 'Bière de Garde', 'Dubbel', 'Faro', 'Flanders Oud Bruin', 'Flanders Red Ale', 'Gueuze', 'Lambic - Fruit', 'Lambic - Unblended', 'Quadrupel (Quad)', 'Saison / Farmhouse Ale', 'Tripel', 'Witbier', 'Baltic Porter', 'Braggot', 'English Barleywine', 'English Bitter', 'English Brown Ale', 'English Dark Mild Ale', 'English India Pale Ale (IPA)', 'English Pale Ale', 'English Pale Mild Ale', 'English Porter', 'English Stout', 'English Strong Ale', 'Extra Special / Strong Bitter (ESB)', 'Foreign / Export Stout', 'Milk / Sweet Stout', 'Oatmeal Stout', 'Old Ale', 'Russian Imperial Stout', 'Winter Warmer', 'Sahti', 'Altbier', 'Berliner Weissbier', 'Dunkelweizen', 'Gose', 'Hefeweizen', 'Kölsch', 'Kristalweizen', 'Roggenbier', 'Weizenbock', 'Irish Dry Stout', 'Irish Red Ale', 'Kvass', 'Scotch Ale / Wee Heavy', 'Scottish Ale', 'Scottish Gruit / Ancient Herbed Ale', 'Lager Styles', 'American Adjunct Lager', 'American Amber / Red Lager', 'American Double / Imperial Pilsner', 'American Malt Liquor', 'American Pale Lager', 'California Common / Steam Beer', 'Light Lager', 'Low Alcohol Beer', 'Czech Pilsener', 'Euro Dark Lager', 'Euro Pale Lager', 'Euro Strong Lager', 'Bock', 'Doppelbock', 'Dortmunder / Export Lager', 'Eisbock', 'German Pilsener', 'Kellerbier / Zwickelbier', 'Maibock / Helles Bock', 'Märzen / Oktoberfest', 'Munich Dunkel Lager', 'Munich Helles Lager', 'Rauchbier', 'Schwarzbier', 'Vienna Lager', 'Happoshu', 'Japanese Rice Lager', 'Fruit / Vegetable Beer', 'Herbed / Spiced Beer', 'Smoked Beer'],
      required: true,
      unique: true
    },
    group: {
      type: 'string',
      enum: ['American Ales', 'Belgian / French Ales', 'English Ales', 'Finnish Ales', 'German Ales', 'Irish Ales', 'Russian Ales', 'Scottish Ales', 'American Lagers', 'Czech Lagers', 'European Lagers', 'German Lagers', 'Japanese Lagers', 'Hybrid Styles'],
      required: true
    }
  }
};

\\ API \\控制器\\ BeerController.js:

module.exports = {

  create: function(req, res){
    console.log(req.body);
    Beer.create(req.body).exec(function createCB(err, beer){
      if (err) return res.send(err);
      res.status(201);
      res.json(beer);
    });
  },

  // a FIND action
  read: function (req, res, next) {
    var id = req.param('id');

    if (id) {
      Beer.findOne(id, function(err, beer) {
        if(beer === undefined) return res.notFound();
        if (err) return res.send(err);
        res.json(beer);
      });

    } else {
        var where = req.param('where');
        if (_.isString(where)) where = JSON.parse(where);
        var options = {
          limit: req.param('limit') || undefined,
          skip: req.param('skip')  || undefined,
          sort: req.param('sort') || undefined,
          where: where || undefined
        };

        Beer.find(options, function(err, beer) {
          if(beer === undefined) return res.notFound();
          if (err) return res.send(err);
          res.json(beer);
        });
    }

  },

};

在\\ config \\ routes.js中:

'post /api/beers': 'BeerController.create',
'get /api/beers/:id?': 'BeerController.read',

兩個要求:

POST /api/beers HTTP/1.1
Host: localhost:1337
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 0fd81643-08ce-7e43-6ed7-c3abafb22700
{"name":"Bud Light Lime","style": {"name": "Light Lager","group": "American Lagers"}, "brewery": {"name": "Anheuser-Busch","countryCode":"us"}, "alcoholByVolume": 4.2, "beerAdvocateId": 41821}

POST /api/beers HTTP/1.1
Host: localhost:1337
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 6e9efbd9-bb10-9748-7e70-229e131fe166
{"name":"Bud Light","style": {"name": "Light Lager","group": "American Lagers"}, "brewery": {"name": "Anheuser-Busch","countryCode":"us"}, "alcoholByVolume": 4.2, "beerAdvocateId": 1320}

第二次請求時出錯:

{
  "error": "E_UNKNOWN",
  "status": 500,
  "summary": "Encountered an unexpected error",
  "raw": {
    "name": "MongoError",
    "code": 11000,
    "err": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: hkbooze.beerstyle.$name_1  dup key: { : \"Light Lager\" }"
  }
}

似乎您正在傳遞stylebrewery JSON。 老實說,我從未嘗試用1個請求填充多個模型。 這真的是Sails的功能嗎? 如果是,它可能仍會每次嘗試創建類別,這會導致唯一性問題。

我的兩種方法是:1)如果類別保持不變,則首先定義類別。 僅傳遞一個ID。 或2)將一些自定義腳本編寫到beforeValidate() ,該腳本會將JSON從請求中刪除,並嘗試按名稱在類別中查找它。 如果找不到任何東西,它將創建一個新類別。 在所有情況下,它都會返回一個ID。

這是一些示例代碼,可能包含缺陷:]

 beforeValidate: function(values, cb){ if(typeof values.style !== 'string'){ Style.find({where: {name: values.style.name}}.exec(function(err, foundStyle){ if(!data){ Style.create(values.style,function(err, newstyle){ if(!err){ values.style = newstyle.id; cb(); } }); } else { values.style = foundStyle.id; cb(); } }); } } 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM