0

我觉得必须有一个简单的解决方案,但我似乎无法找到正确的方法来在线搜索它。我在 Node.js & Express 上使用 Sails 服务器。现在我正在尝试让一个基本的 CRUD API 工作,所以我一直在发送 post & get connection with Postman

我从一个空数据库(托管在 Mongolab 上)开始,并尝试创建两个名称不同但类别相同的文档。之后,我希望类别集合中只有 1 个文档,主集合中只有两个文档。相反,第二个 POST 触发了错误,因为尽管有 {unique:true} 属性,它仍试图创建第二个类别文档。

我能做些什么来修复这个错误并建立正确的一对多关系?

\api\models\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\models\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\models\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\controllers\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\" }"
  }
}
4

1 回答 1

1

似乎您正在为styleand传递 JSON brewery。老实说,我从来没有尝试用这样的 1 个请求填充多个模型。这真的是 Sails 的一个功能吗?如果是,它仍然可能每次都尝试创建一个类别,这会导致唯一性问题。

My two ways of doing this would be: 1) Define the categories first if they stay the same. Pass just an id. or 2) Write some custom script probably into beforeValidate() which would take the JSON out of the request, tried to find it in categories by name. If it couldnt find anything, it would create a new category. In all cases, it would return an ID.

this is some example code, it may contain flaws:]

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();
              }
            });
		}
	}

于 2014-11-29T07:57:26.173 回答