Search code examples
c#mongodbperformancemongodb-querymongodb-.net-driver

MongoDB C# Driver - Fastest way to perform an "IN" query on _id


I'm trying to get values from a collection, based on items whose IDs are in a certain collection of IDs.

My current code to build the filter is:

        IEnumerable<string> IDList;

        using (var enumerator = IDList.GetEnumerator())
        {
            if (enumerator.MoveNext() == false) return null; // empty collection

            // take the first key
            var key = enumerator.Current;
            filter = Builders<MyClass>.Filter.Eq(p => p.Key, key);

            // take all the other keys
            while (enumerator.MoveNext())
            {
                var innerKey = enumerator.Current;
                filter = filter | Builders<MyClass>.Filter.Eq(p => p.Key, innerKey);
            }
        }

and then my code to get the items is:

        List<MyClass> values = new List<MyClass>();

        using (var cursor = await MyCollection.FindAsync(filter))
        {
            while (await cursor.MoveNextAsync())
            {
                values.AddRange(cursor.Current);
            }
        }

This code's performance seems pretty subpar, and I'm sure there has to be a faster way since MongoDB should have very good performance... Not to mention I'm querying an indexed field, which should make the query very fast. What can I do to speed this up, both in an async way and a sync way? From some Googling I've seen that there are many ways to query a collection, and I'm not sure which way would be the best for my particular case.

Running this query in RoboMongo takes 0.02 seconds, while running it in C# MongoDb.Driver takes a full second, sometimes even longer and I'm not sure why.

Thanks in advance.


Solution

  • How about a simple "$in" query?

    using MongoDB.Bson;
    using MongoDB.Driver;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        public class MyClass
        {
            public ObjectId Id;
            public string Key;
        }
    
        public class Program
        {
            static void Main(string[] args)
            {
                IEnumerable<string> ids = new [] { "a", "b", "c" };
    
                var collection = new MongoClient().GetDatabase("test").GetCollection<MyClass>("test");
    
                foreach (var id in ids)
                {
                    collection.InsertOne(new MyClass { Key = id });
                }
    
                // here comes the "$in" query
                var filter = Builders<MyClass>.Filter.In(myClass => myClass.Key, ids);
    
                // sync
                List<MyClass> values = collection.Find(filter).ToList();
    
                // async
                var queryTask = collection.FindAsync(filter);
                values = GetValues(queryTask).Result;
    
                Console.ReadLine();
            }
    
            private static async Task<List<MyClass>> GetValues(System.Threading.Tasks.Task<IAsyncCursor<MyClass>> queryTask)
            {
                var cursor = await queryTask;
                return await cursor.ToListAsync<MyClass>();
            }
        }
    }