Mongodb 是什么导致meteor应用程序有时创建两个文档?

Mongodb 是什么导致meteor应用程序有时创建两个文档?,mongodb,meteor,Mongodb,Meteor,我有一个meteor应用程序,它将文章的文本拆分为段落、句子、单词和字符,然后将其存储在json中,然后将其保存为集合中的文档。我正在测试的文档现在在mongodb中以15133字节结束 当我插入文档时,插入大约需要20或30秒。然后,有时它会再次执行我的文章创建例程并插入另一个文档。有时它会插入3个或更多文档。有时,它的行为与它应该的一样,只向集合中插入一个文档 我应该寻找什么可能导致这种行为 这是我的代码,按要求: Meteor.methods({ 'createArticle': func

我有一个meteor应用程序,它将文章的文本拆分为段落、句子、单词和字符,然后将其存储在json中,然后将其保存为集合中的文档。我正在测试的文档现在在mongodb中以15133字节结束

当我插入文档时,插入大约需要20或30秒。然后,有时它会再次执行我的文章创建例程并插入另一个文档。有时它会插入3个或更多文档。有时,它的行为与它应该的一样,只向集合中插入一个文档

我应该寻找什么可能导致这种行为

这是我的代码,按要求:

Meteor.methods({
'createArticle': function (text, title) {
    var article = {}
    article.title = title
    article.userID = "sdfgsdfg"
    article.text = text
    article.paragraphs = []
    var paragraphs = splitArticleIntoParagraphs(text)
    console.log("paragraphs", paragraphs)
    _.each(paragraphs, function (paragraph, p) {
        if (paragraph !== "") {
            console.log("paragraph", paragraph)
            article.paragraphs[p] = {}
            article.paragraphs[p].read = false
            article.paragraphs[p].text = paragraph
            console.log("paragraphs[p]", article.paragraphs[p])
            var sentences = splitParagraphIntoSentences(paragraph)
            article.paragraphs[p].sentences = []
        }
        _.each(sentences, function (sentence, s) {
            if (sentence !== "") {
                article.paragraphs[p].sentences[s] = {}
                console.log("sentence", sentence)
                article.paragraphs[p].sentences[s].text = sentence
                article.paragraphs[p].sentences[s].read = false
                console.log("paragraphs[p].sentences[s]", article.paragraphs[p].sentences[s])
                var wordsForward = splitSentenceIntoWordsForward(sentence)
                console.log("wordsForward", JSON.stringify(wordsForward))
                article.paragraphs[p].sentences[s].forward = {}
                article.paragraphs[p].sentences[s].forward.words = wordsForward

                // var wordsReverse = splitSentenceIntoWordsReverse(sentence)
                _.each(wordsForward, function (word, w) {
                    if (word) {
                        // console.log("word", JSON.stringify(word))
                        // article.paragraphs[p].sentences[s] = {}
                        // article.paragraphs[p].sentences[s].forward = {}
                        // article.paragraphs[p].sentences[s].forward.words = []
                        article.paragraphs[p].sentences[s].forward.words[w] = {}
                        article.paragraphs[p].sentences[s].forward.words[w].wordID = word._id
                        article.paragraphs[p].sentences[s].forward.words[w].simp = word.simp
                        article.paragraphs[p].sentences[s].forward.words[w].trad = word.trad
                        console.log("word.simp", word.simp)
                        var characters = word.simp.split('')
                        console.log("characters", characters)
                        article.paragraphs[p].sentences[s].forward.words[w].characters = []
                        _.each(characters, function (character, c) {
                            if (character) {
                                console.log("character", character, p, s, w, c)
                                article.paragraphs[p].sentences[s].forward.words[w].characters[c] = {}
                                article.paragraphs[p].sentences[s].forward.words[w].characters[c].text = character
                                article.paragraphs[p].sentences[s].forward.words[w].characters[c].wordID = Words.findOne({simp: character})._id
                            }
                        })
                    }
                })
            }
        })
    })
    // console.log("article", JSON.stringify(article))
    // console.log(JSON.stringify(article.paragraphs[10].sentences[1].forward))//.words[4].characters[0])
    console.log("done")
    var id = Articles.insert(article)
    console.log("id", id)
    return id
}
})
我在这里调用该方法:

Template.articleList.events({
"click #addArticle": function(event) {
    event.preventDefault();
    var title = $('#title').val();
    var text = $('#text').val();
    $('#title').value = '';
    $('#text').value = '';
    $('#text').attr('rows', '3');
    Meteor.call('createArticle', text, title);
 }
})

需要记住的一件重要事情是,meteor方法在执行CPU密集型任务时效果不佳。由于meteor服务器只在单个线程中工作,因此任何类型的阻塞计算(如您的阻塞计算)都会影响所有客户端连接,例如延迟DDP心跳。这反过来会导致客户端认为连接已断开

正如@ghybs在其中一条评论中所建议的,您的方法可能会被一个不耐烦的DDP客户端触发多次,该客户端认为服务器已断开连接。防止这种行为的最简单方法是将
noRetry
标志添加到
Meteor。应用
如下所述:

我相信Meteor.call
没有这个选项

另一个策略是尝试确保方法是幂等的,即多次调用它们不会产生任何额外的效果。这通常是正确的-至少当您使用方法模拟时是如此-因为重试db insert将重复使用相同的文档
id
,第二次尝试将失败。出于某种原因,你的情况下不会发生这种情况

最后,您描述的问题清楚地表明,对于像您这样的计算代价高昂的任务,可能应该使用不同的模式。如果我是你,我会先把工作分成几个步骤:

  • 首先,我要确保文档是通过POST请求而不是通过DDP上传到服务器的
  • 然后,我将实现一个“processfile”服务器端方法,该方法获取已经在服务器或数据库中的文件(如果使用files集合)。该方法应该做的第一件事是调用this.unblock()
  • ,但这还不是全部
  • 理想情况下,计算任务应该在一个单独的进程中执行。只有当该过程完成时,该方法才会返回,告诉实际调用方作业已完成。但由于我们调用了
    this.unblock()
    ,调用方可以执行不同的任务,例如在等待结果时调用其他方法/订阅

  • 有时,有一个单独的过程是不够的。我曾经遇到过必须将任务委托给另一个工作者服务器的情况。

    需要记住的一点是,meteor方法在执行CPU密集型任务时效果不佳。由于meteor服务器只在单个线程中工作,因此任何类型的阻塞计算(如您的阻塞计算)都会影响所有客户端连接,例如延迟DDP心跳。这反过来会导致客户端认为连接已断开

    正如@ghybs在其中一条评论中所建议的,您的方法可能会被一个不耐烦的DDP客户端触发多次,该客户端认为服务器已断开连接。防止这种行为的最简单方法是将
    noRetry
    标志添加到
    Meteor。应用
    如下所述:

    我相信Meteor.call
    没有这个选项

    另一个策略是尝试确保方法是幂等的,即多次调用它们不会产生任何额外的效果。这通常是正确的-至少当您使用方法模拟时是如此-因为重试db insert将重复使用相同的文档
    id
    ,第二次尝试将失败。出于某种原因,你的情况下不会发生这种情况

    最后,您描述的问题清楚地表明,对于像您这样的计算代价高昂的任务,可能应该使用不同的模式。如果我是你,我会先把工作分成几个步骤:

  • 首先,我要确保文档是通过POST请求而不是通过DDP上传到服务器的
  • 然后,我将实现一个“processfile”服务器端方法,该方法获取已经在服务器或数据库中的文件(如果使用files集合)。该方法应该做的第一件事是调用this.unblock()
  • ,但这还不是全部
  • 理想情况下,计算任务应该在一个单独的进程中执行。只有当该过程完成时,该方法才会返回,告诉实际调用方作业已完成。但由于我们调用了
    this.unblock()
    ,调用方可以执行不同的任务,例如在等待结果时调用其他方法/订阅

  • 有时,有一个单独的过程是不够的。我曾经遇到过必须将任务委托给其他工作服务器的情况。

    请编辑您的问题并添加相关代码。在插入文章之前,您是否可以检查它是否等待u.each()(全部)?这可能就是罪魁祸首。另外,请添加调用方法的位置,以防添加方法调用。那么,你是说我应该插入这篇文章,然后在它通过u.each时更新它?在
    console.log(“done”)
    no之后大约需要20到30秒,我是说您应该检查它是立即插入还是在拆分完成之后插入。我可能会在客户端进行拆分,顺便说一句,这里可能不是您的情况,但请记住,如果客户没有收到结果(或错误)