使用 mongoose 将多个不存在的文档插入 MongoDB

Posted

技术标签:

【中文标题】使用 mongoose 将多个不存在的文档插入 MongoDB【英文标题】:Insert multiple none-existed documents to MongoDB using mongoose 【发布时间】:2018-09-20 12:38:14 【问题描述】:

我想保存多个文档,这些文档是在以井号“#”表示的帖子上找到的标签。我在数组中有标签。例如:

var tags = ['banana', 'apple', 'orange', 'pie']

我遍历它们并将它们转换为文档对象(以将它们插入数据库)。问题是我想将一个 new 文档插入到集合中,前提是它之前从未插入过。如果它在我想将插入文档的userCounter 属性增加一之前插入。

var tags = ['banana', 'apple', 'pie', 'orange'];

var docs = tags.map(function(tagTitle) 
  return 
    title: tagTitle,
    // useCounter: ??????????
  ;
);

var Hashtag = require('./models/Hashtag');

/**
* it creates multiple documents even if a document already exists in the collection,
* I want to increment useCounter property of each document if they exist in the collection;
* not creating new ones.
* for example if a document with title ptoperty of 'banana' is inserted before, now increment
* document useCounter value by one. and if apple never inserted to collection, create a new document 
* with title of 'apple' and set '1' as its initial useCounter value
*/

Hashtag.create(docs)
.then(function(createdDocs) 

)
.then(null, function(err) 
  //handle errors
);

【问题讨论】:

【参考方案1】:
async function findOrIncrease(title)       
   let hashtag = await Hashtag.findOne(title);
   if(hashtag) 
     hashtag.userCounter++;
    else 
     hashtag = new Hashtag(title, userCounter: 1);
   
   await hashtag.save();
 

可用作:

  (async function() 
    for(const title of tags)
      await findOrIncrease(title);
  )()

或者如果你想并行执行:

  tags.forEach(findOrIncrease);

您可以通过使用 mongodbs 索引来加快速度。

【讨论】:

【参考方案2】:

感谢@Jonas W 的回复,我还找到了另一个解决方案。我认为基于标签数组做出一些承诺并从这些承诺中解析标签文档(或出于某些原因拒绝它们)可能会更好(因为它在性能方面更清晰、更快)。然后使用Promise.all() 做出提供猫鼬文档的完整承诺(根据某些条件创建或更新)。是这样的:

// some other chains
.then((xxxx) => 
        const hashtagsTitles = require('../../src/hashtags/hashtagParser').hashtags(req.newPost.caption);
        const Hashtag = require('../../src/database/models/Hashtag');

        let findOrIncrease = title =>
            new Promise((resolve, reject) => 
                Hashtag.findOne(
                        title
                    )
                    .then((hashtag) => 
                        if (!hashtag) 
                            new Hashtag(
                                    title,
                                    usageCount: 0
                                ).save()
                                .then(hashtag => resolve(hashtag._id))
                                .catch(err => reject(err));
                         else 
                            hashtag.usageCount++;
                            hashtag.save()
                                .then(hashtag => resolve(hashtag._id))
                                .catch(err => reject(err));
                        
                    )
                    .catch(err => reject(err));
            );

        let promiseArr = hashtagsTitles.map((hashtagTitle) =>
            findOrIncrease(hashtagTitle)
        );

        return Promise.all(promiseArr)
            .then(results => results)
            .catch(err => 
                throw err
            );
    )
    .then((hashtags) => 
        hashtags.forEach((hashtag) => req.newPost.hashtags.push(hashtag));
    )
    //there might be some other chains

这里还有一个很好的指南: Mongoose - Create document if not exists, otherwise, update- return document in either case

【讨论】:

***.com/questions/23803743/… 我在 github 上阅读了这篇文章和其他一些文章。他们唯一注意到的危害是我处理它们的未处理错误(如您在代码中所见)。我也觉得没那么复杂。它只是一个承诺,它在其他一些承诺(可能由 api 提供)处理程序的上下文中解析为一个值。请告诉我它是反模式的主要原因是什么? 好吧,您可以将 promise 链接起来,使其更具可读性。实际上,这与我上面的代码完全相同相同,只是多几行:) 使用您的代码如何将每个创建(或增加)的文档的 ID 推送到一个空数组? Promise.all(tags.map(findOrIncrease))

以上是关于使用 mongoose 将多个不存在的文档插入 MongoDB的主要内容,如果未能解决你的问题,请参考以下文章

使用 mongoose 一次将多个 ObjectId 插入子文档

Mongoose 更新或插入许多文档

Mongoose 中的多个文档更新插入

链接多个 Promise,使用 map 循环数组并创建 mongoose 文档?

如何使用 Mongoose 将文档插入只有一个 ObjectID 的集合中?

如果未找到 ID,则 Mongoose 更新文档或插入新文档(Express REST API)