首页 > 解决方案 > 判断一组 id 中的哪些 id 仍在数据库中的有效方法(即,将输入 id 与集合 id 相交)MongoDb C#

问题描述

我有一个包含大约 8000 万份文档的集合。通过 API,用户可以验证数据库中是否仍然存在一组 id(输入集)。输入集可能相当大,但我会将验证分成大约几块。10000 个 ID。基本上我想得到数据库ID和输入集之间的交集。

我想用 Linq 做到这一点,但欢迎提出其他建议。

下面是一些示例代码,显示了我的场景以及我到目前为止所尝试的内容。

第一种方法是我会做的,但它会抛出 NotSupportedException :表达式树中不支持方法 Intersect :

第二种方法有效,但在大型集上确实很慢。

第三种方法比第二种方法快,但是我必须在内存中加载 8000 万个 id。

我们试图坚持使用 C# 包装器提供的 linq 接口,但有时这很困难。任何指针表示赞赏。我想有一种方法可以通过 $setIntersection 使用不同的构建器和管道定义,但我无法理解关于此的 c# 文档。

  private string[] FilterOnExistInDatabase1(string[] candidates)
    {
        // Query<T> is just a wrapper to the collection and returns a IQueryable<T>
        return mongoRepository.Query<TestModel>().Select(x => x.Id).Intersect(candidates).ToArray();
    }

    private string[] FilterOnExistInDatabase2(string[] candidates)
    {
        // Query<T> is just a wrapper to the collection and returns a IQueryable<T>
        return mongoRepository.Query<TestModel>().Select(x => x.Id).Where(x => candidates.Contains(x)).ToArray();
    }

    private string[] FilterOnExistInDatabase3(string[] candidates)
    {
        // Query<T> is just a wrapper to the collection and returns a IQueryable<T>
        var allExistingIds = mongoRepository.Query<TestModel>().Select(x => x.Id).ToArray();
        var existingCandidates = allExistingIds.Intersect(candidates).ToArray();
        return existingCandidates;
    }

    [Test]
    public void SampleQuery()
    {
        var models = Enumerable.Range(0, 10).Select(x => new TestModel()).ToArray();
        mongoRepository.InsertMany(models, CancellationToken.None);

        var deletedId = "I no longer exist";
        var candidates = models.Select(x => x.Id).Concat(new []{deletedId}).ToArray();
        var existingCandidates = FilterOnExistInDatabase3(candidates);

        Assert.That(existingCandidates.Length, Is.EqualTo(models.Length));
        Assert.False(existingCandidates.Contains(deletedId));
        Assert.That(existingCandidates.Length, Is.EqualTo(candidates.Length - 1));

    }

标签: c#mongodb

解决方案


下面的方法怎么样?基本上,您会取回数据库中存在的 ID 数组,并使用 linq 在客户端生成交集以获取无效/已删除的 ID。

using MongoDB.Bson;
using MongoDB.Entities;
using MongoDB.Entities.Core;
using System;
using System.Linq;

namespace StackOverflow
{
    public class Item : Entity
    {
        public string Name { get; set; }
    }

    public class Program
    {
        private static void Main(string[] args)
        {
            new DB("test", "localhost");

            var one = new Item { Name = "one" }; one.Save();
            var two = new Item { Name = "two" }; two.Save();
            var thr = new Item { Name = "three" }; thr.Save();

            var inputIDs = new[] { one.ID, two.ID, ObjectId.GenerateNewId().ToString() };

            var validIDs = DB.Queryable<Item>() // for official driver use: collection.AsQueryable()
                             .Where(i => inputIDs.Contains(i.ID))
                             .Select(i => i.ID)
                             .ToArray();

            var deletedIDs = inputIDs.Except(validIDs).ToArray();
        }
    }
}

从理论上讲,这应该比上面的第二种方法更快,因为它不会导致集合中每个 ID 的投影。如果您可以接受这种方法,我很想知道 mongodb 完成 8000 万个文档的任务需要多少毫秒。


推荐阅读