Javascript mongoDB中在同一API中并行查询同一文档

Javascript mongoDB中在同一API中并行查询同一文档,javascript,mongodb,typescript,promise,parallel-processing,Javascript,Mongodb,Typescript,Promise,Parallel Processing,我有一个用typescript编写的API,我尝试使用promise.allSetted为同一文档运行并行查询,但是它的性能更差,我猜它们是按顺序运行的。是否有一种方法可以在mongoDB的同一连接中对同一文档执行并行查询。代码如下: console.time("normal"); let normal = await ContentRepo.geBySkillIdWithSourceFiltered( [chosenSkillsArr[0].sid!], r

我有一个用typescript编写的API,我尝试使用promise.allSetted为同一文档运行并行查询,但是它的性能更差,我猜它们是按顺序运行的。是否有一种方法可以在mongoDB的同一连接中对同一文档执行并行查询。代码如下:

console.time("normal");
let normal = await ContentRepo.geBySkillIdWithSourceFiltered(
    [chosenSkillsArr[0].sid!],
    readContentIds,
    body.isVideoIncluded,
    true,
    true
);
console.timeEnd("normal");

console.time("parallel");
const parallel = await Promise.allSettled(
    chosenSkillsArr.map(async (skill: IScrapeSkillDocument) => {
        const result = await ContentRepo.geBySkillIdWithSourceFiltered(
            [skill.sid!],
            readContentIds,
            body.isVideoIncluded,
            true,
            true
        );
    })
);
console.timeEnd("parallel");
我调用的函数如下:

async geBySkillIdWithSourceFiltered(
    skillIds: string[],
    contentIds: string[],
    isVideoIncluded?: boolean,
    isCuratorIdFilter?: boolean,
    activeSourceFilter?: boolean
): Promise<IContentWithSource[]> {
    try {
        console.time(`single-${skillIds}`);
        var contents = await ContentM.find({
            $and: [
                { "skills.skillId": { $in: skillIds } },
                { recordStatus: true },
                isCuratorIdFilter ? { curatorId: 0 } : {},
                isVideoIncluded ? {} : { type: contentTypeNumber.read },
                { _id: { $nin: contentIds } },
            ],
        }).exec();
        var items: IContentWithSource[] = [];
        var sourceIds = new Set<string>();
        contents.forEach((content) => {
            if (!this.isEmpty(content.sourceId)) {
                sourceIds.add(content.sourceId!);
            }
        });
        var sources: any = {};
        var sourcesArr = await new SourceRepo().getByIds(
            Array.from(sourceIds)
        );
        sourcesArr.forEach((source) => {
            sources[source._id] = source;
        });

        if (activeSourceFilter) {
            contents
                .map((i) => i.toJSON() as IContentWithSource)
                .map((k) => {
                    if (sources[k.sourceId!].isActive) {
                        k.source = sources[k.sourceId!];
                        items.push(k);
                    }
                });
        } else {
            contents
                .map((i) => i.toJSON() as IContentWithSource)
                .map((k) => {
                    k.source = sources[k.sourceId!];
                    items.push(k);
                });
        }
        console.timeEnd(`single-${skillIds}`);

        return items;
    } catch (err) {
        throw err;
    }
}

看起来您在并行版本中运行了更多的代码

//正常版本
let normal=wait ContentRepo.geBySkillIdWithSourceFiltered(
[chosenSkillsArr[0].sid!],
ReadContentID,
包括body.com在内,
是的,
真的
);
//并行版本中的代码:
chosenSkillsArr.map(异步(技能:isccilldocument)=>{
const result=wait ContentRepo.geBySkillIdWithSourceFiltered(
[skill.sid!],
ReadContentID,
包括body.com在内,
是的,
真的
);
})
对于并行版本,将函数调用(
ContentRepo.geBySkillIdWithSourceFiltered
)放入循环中。这就是为什么它比较慢

关于并行运行承诺的问题: 像
Promise.all
Promise.allsolited
等待多个承诺。它不关心它们解析的顺序,也不关心计算是否并行运行。它们都不能保证并发性,也不能保证相反的情况。他们的任务只是确保传递给它的所有承诺都得到履行

因此,您无法手动保证承诺执行的并行性

下面是一个真正解释并行性和
承诺的例子。所有的
以及浏览器Nodejs API在并行性方面与计算机上安装的Nodejs API的区别

以下是文章结论的摘录:

JavaScript运行时是单线程的。我们无法访问JavaScript中的线程。即使您有多核CPU,也无法使用JavaScript并行运行任务。但是,browser/NodeJS使用C/C++(!)来访问线程。因此,它们可以实现并行性

旁注: 有一个细微的区别:

  • Promise.all:仅当传递给它的所有承诺都已解决时才解决,否则它将拒绝第一个已拒绝的承诺错误

  • Promise.allSettled:将始终使用包含有关已解决和已拒绝承诺的信息的数组进行解决


  • 谢谢你的精彩解释。我试着答应,但没有使用地图,而是手工提出请求。但这并没有改变任何事情。我想这可能是与mongoDb有关的问题。您对在mongoDb中运行并行查询有何想法?我认为这不是mongoDb的问题,而是NodeJ的自治性及其单线程性。假设有10个人跑向柜台去买电影票。所有这些都是在完全相同的地点和时间开始的。有人会先到,柜台的职员会为最先到的人服务。考虑CPU和10个人的计数器是10个不同的承诺。无论是谁先开始,还是有人离柜台有多近,柜台一次只能为一个人服务。Nodejs就是这样。非常感谢您的帮助,那么我应该寻找其他方法来提高查询性能。很高兴我回答了您的问题。至少有一部分。请注意,尽可能避免将数据库调用放入循环中。
    single-KS120B874P2P6BK1MQ0T: 1872.735ms
    normal: 1873.934ms
    single-KS120B874P2P6BK1MQ0T: 3369.925ms
    single-KS440QS66YCBN23Y8K25: 3721.214ms
    single-KS1226Y6DNDT05G7FJ4J: 3799.050ms
    parallel: 3800.586ms
    
    [chosenSkillsArr[0].sid!], vs  chosenSkillsArr.map()