Search code examples
c#mongodbmongodb-.net-driver

Find maximal value for field in all collections


I have an database containing collections, and these collections containing documents on the form:

{ "_id" : 4, "value" : 2 }

I want to find the maximum "_id" in all the collections in a efficient way. At the moment, I have a working method:

public long getLastTimestamp()
{
    var tempList = getChannelNames();
    var channelList = new List<IMongoCollection<BsonDocument>>();
    var docuList = new List<BsonDocument>();

    foreach (var channel in tempList)
    {
        channelList.Add(_database.GetCollection<BsonDocument>(channel.name));
    }

    foreach (var channel in channelList)
    {
        var filter = Builders<BsonDocument>.Filter.Exists("_id");
        var result = channel.FindAsync(filter).Result.ToList();

        foreach (var docu in result)
        {
            docuList.Add(docu);
        }
    }

    var timeList = new List<long>();

    foreach (var docu in docuList)
    {
        Console.WriteLine(docu);
        if (!docu["_id"].IsObjectId)
            timeList.Add(docu["_id"].ToInt64());
    }

    return timeList.Max();
}

It works, but I don't think it's very efficient. Does anyone have some input or advice?

EDIT: I ended up doing this:

    public long getLastTimestamp()
    {
        var filter = Builders<BsonDocument>.Filter.Exists("value");
        return getChannelNames()
            .Select(channel => _database.GetCollection<BsonDocument>(channel.name))
            .SelectMany(channel => channel.FindAsync(filter).Result.ToList())
            .Max(docu => docu["_id"].ToInt64());
    }

Solution

  • Check this out:

    public long getLastTimestamp()
    {
        //var tempList = getChannelNames();
        var channelList = new List<IMongoCollection<BsonDocument>>();
        var docuList = new List<BsonDocument>();
    
        foreach (var channel in getChannelNames())
        {
            var filter = Builders<BsonDocument>.Filter.Exists("_id");
            var result = _database.GetCollection<BsonDocument>(channel.name)
                         .FindAsync(filter).Result.ToList();
    
            return result.Where(x => !x["_id"].IsObjectId)
                   .Max(entry => entry["_id"].ToInt64);
        }
    
        return 0;
    }
    

    Couldnt test it as these objects arnt available to me. On the linq-part you would maybe have to convert to list or array to get Where() and Max() available.

    Storing and iterating again is always slower.

    public long getLastTimestamp()
    {
        var filter = Builders<BsonDocument>.Filter.Exists("_id");
    
        return getChannelNames()
        .Select(channel => _database.GetCollection<BsonDocument>(channel.name).FindAsync(filter).Result.ToList())
        .Where(doc => !doc["_id"].IsObjectId)
        .Max(doc => doc["_id"].ToInt64);
    }