Search code examples
c#multithreadingmongodbmongodb-.net-driver

MongoDB C# Driver and server generated ObjectIds


Is there a way get server generated ObjectIds instead of C# Driver generated ObjectIds? Using MongoCollectionSettings.AssignIdOnInsert = false only gets you zeroed out ObjectIds. I'm doing multi-threaded inserts on a capped collection, and I'm seeing threads switch between the ObjectId generation and the insert. This causes out of order ObjectIds in a collection that's supposed to be ordered for tailed cursors sorting on natural order. Right now I'm using a static lock object for the inserts, but that won't help with different executables/servers.

It appears this is possible with the pymongo driver: ObjectID generated by server on pymongo


Solution

  • Getting documents in insertion order from a capped collection

    Capped collections maintain documents in insertion order, so you should ideally use natural order rather than relying on the timestamp in the generated _id. Your tailable cursor will be reading documents in natural order, so should not make any assumptions based on the _id.

    Generating server-side _id

    To generate _id on the server side using the C# driver you need to:

    • set the class attribute [BsonIgnoreIfDefault]
    • set the collection attribute AssignIdOnInsert = false
    • insert a document without an _id

    Example:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using MongoDB.Bson;
    using MongoDB.Driver;
    using MongoDB.Bson.Serialization.Attributes;
    
    public class MyDoc {
        [BsonIgnoreIfDefault]
        public ObjectId? Id;
        public int X;
    }
    
    public static class Program {
        public static void Main(string[] args) {
            MongoClient client = new MongoClient(); // connect to localhost
            var server = client.GetServer ();
            var database = server.GetDatabase("test");
            var collectionSettings = new MongoCollectionSettings { AssignIdOnInsert = false };
            var collection = database.GetCollection<MyDoc>("nullid", collectionSettings);
    
            // Insert document without _id
            collection.Insert(new MyDoc { X = 1});
        }
    }