复杂的猫鼬从api中提取数据列表并插入到mongodb中,如果它还没有存在的话

时间:2017-04-02 10:07:32

标签: node.js mongodb api mongoose

我使用Nodejs中的RapidAPI模块连接到Yelp API。我能够请求令牌,连接和请求数据,检索数据,并将每个结果的相关信息插入mongodb。这里变得复杂......

我们说我做了一个Yelp API请求并搜索条形图。我得到一个条形列表并将它们插入数据库。让我们说列表中的其中一个是" Joe Bar&烤架&#34 ;.我的mongodb中的一个字段是" type"它是一个数组。所以现在,这个特定的文档看起来像这样:

{
  id: 'joes-bar-and-grill',
  name: 'Joe\'s Bar & Grill',
  type: ['bar']
}

然后我在"餐馆"上的Yelp API上运行另一个请求,并在此列表" Joe's Bar&烤架"再次出现。我没有将新的重复文档插入mongodb,而是希望现有文档最终看起来像这样:

{
  id: 'joes-bar-and-grill',
  name: 'Joe\'s Bar & Grill',
  type: ['bar', 'restaurant']
}

除此之外,我们再次为" bars"和" Joe"" Joe烤架"又来了。我不希望它自动插入" bar"再次进入type数组,如果" bar"已存在于其数组中。

我已尝试将findOneAndUpdate upsert: true$push新数据加入到数组中,但我根本无法使用它。有没有人有任何想法?

2 个答案:

答案 0 :(得分:1)

您可以使用findOneAndUpdate,结合$addToSet(以确保数组中的条目仅存在一次)和$each(以允许将数组传递给$addToSet ):

Bar.findOneAndUpdate({ id : 'joes-bar-and-grill' }, {
  id        : 'joes-bar-and-grill',
  name      : 'Joe\'s Bar & Grill',
  $addToSet : { type : { $each : [ 'restaurant' ] } }
}, { upsert : true })

编辑:既然您发布了整个代码,问题就变得更加明显了。

首先,我不确定你传递给Location.update()的第三和第四个论点是否有意义。据我所知,第三个应该是选项对象,第四个应该是异步函数

其次,看起来你只是忽略了任何更新错误。

最后,这不起作用:

for (var i = 0; i < payload.businesses.length; i++) { Location.update(...) }

由于Location.update()是异步的,i变量会被破坏(您应该在SO上浏览以找到相应的解释;例如,see this question)。

您将需要一个能够为您提供更好的异步支持的库,最好还有一个可以帮助限制更新查询数量的库。

一旦这样的库async并使用它,您的代码就会变成这样:

const async = require('async');

...

async.eachLimit(payload.businesses, 5, function(business, callback) {
  Location.update({ yelpID : business.id }, {
    name      : business.name,
    latitude  : business.location.latitude,
    longitude : business.location.longitude,
    address1  : business.location.address1,
    address2  : business.location.address2,
    address3  : business.location.address3,
    city      : business.location.city,
    state     : business.location.state,
    zip_code  : business.location.zip_code,
    country   : business.location.country,
    timezone  : 'CST'
    $addToSet : { type : 'bar' }
  }, { upsert : true }, callback);
}, function(err) {
  if (err) {
    console.error(err);
  } else {
    console.log('All documents inserted');
  }
});

答案 1 :(得分:-1)

您可以使用$addToSet运算符

  

$ addToSet运算符向数组添加值,除非值为   已存在,在这种情况下,$ addToSet对该数组不执行任何操作。

     

$ addToSet仅确保没有重复项添加到   设置并不会影响现有的重复元素。 $ addToSet   不保证修改集中元素的特定排序。

     

如果要更新的文档中没有该字段,则$ addToSet会创建   具有指定值作为其元素的数组字段。

     

如果该字段不是数组,则操作将失败。

以下解决方案假定在每次更新时,您会收到单个类型而不是数组。如果输入文档本身是一个数组,您可以使用robertklep的$each运算符解决方案

db.mycoll.update(
   { "id" : "joes-bar-and-grill" },
   {
      $set:{
           name : 'Joe\'s Bar & Grill',
      },
      $addToSet : { type : 'restaurant' }
   },
   true, false);

我还使用了$set运算符。

  

$ set运算符用指定的值替换字段的值   值。

     

$ set运算符表达式具有以下形式:

     

{$ set:{field1:value1,...}}

这是mongo shell输出进一步解释:

> db.mycoll.find({ "id" : "joes-bar-and-grill" });
  // NO RESULT

> db.mycoll.update(
...    { "id" : "joes-bar-and-grill" },
...    {
...       $set:{
...            name : 'Joe\'s Bar & Grill',
...       },
...       $addToSet : { type : 'restaurant' }
...    },
...    true, false);
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 1,
    "nModified" : 0,
    "_id" : ObjectId("58e719b4d543c5e30d615d59")
})
 // INSERTED A NEW DOCUMENT AS IT DOES NOT EXIST

> db.mycoll.find({ "id" : "joes-bar-and-grill" }); // FINDING THE OBJECT
{ "_id" : ObjectId("58e719b4d543c5e30d615d59"), "id" : "joes-bar-and-grill", "name" : "Joe's Bar & Grill", "type" : [ "restaurant" ] }


> db.mycoll.update(
...    { "id" : "joes-bar-and-grill" },
...    {
...       $set:{
...            name : 'Joe\'s Bar & Grill',
...       },
...       $addToSet : { type : 'bar' }
...    },
...    true, false);
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// UPDATING THE DOCUMENT WITH NEW TYPE : "bar"

> db.mycoll.findOne({ "id" : "joes-bar-and-grill" });
{
    "_id" : ObjectId("58e719b4d543c5e30d615d59"),
    "id" : "joes-bar-and-grill",
    "name" : "Joe's Bar & Grill",
    "type" : [
        "restaurant",
        "bar"
    ]
}