2016-11-29 3 views
1

У меня есть база данных, содержащей коллекции, и эти коллекции, содержащих документы по форме:Найти максимальное значение поля во всех коллекциях

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

Я хочу, чтобы найти максимальную "_id" во всех коллекциях в эффективном способе. На данный момент у меня есть метод работы:

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(); 
} 

Это работает, но я не думаю, что он очень эффективен. У кого-нибудь есть какой-нибудь вклад или совет?

EDIT: я в конечном итоге делает это:

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()); 
    } 
+0

Вы могли бы по крайней мере объединить свои первые два цикла foreach. – C4u

+0

А, да. Глупо мне не делать: P Исправлено! –

+0

Также можно комбинировать последние две петли. Добавление элементов в список внутри цикла, только для повторения этого нового списка позже, не нужно. –

ответ

2

Проверьте это:

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 тест как эти объекты ARNT мне доступны. На linq-части вам, возможно, придется преобразовать в список или массив, чтобы получить Where() и Max().

Хранение и повторное повторение всегда происходит медленнее.

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); 
} 
+0

Linq не означает лучшие показатели. вы можете проверить код этих расширений, и вы увидите, что это обычно не так хорошо, потому что они управляют большим количеством случаев использования, тогда выполняется больше кода. – Demonia

+1

@Demonia согласился. Но он уверен, что более эффективен, чем копирование коллекции три раза. –

+0

@Demonia Я havnt использовал linq только потому, что думал, что это обеспечит лучшую производительность. Первоначальная версия имела «foreach» в этой точке, которая сохраняла данные в список тем в случае условия. Переход с linq, чтобы получить условие + получение максимального значения, было правильным, о чем я думал, не сохраняя ничего временно. – C4u

2

Что-то вроде этого?

var filter = Builders<BsonDocument>.Filter.Exists("_id"); 

getChannelNames() 
    .SelectMany(channel => _database.GetCollection<BsonDocument>(channel.name)) 
    .SelectMany(channel => channel.FindAsync(filter).Result.ToList()) // Even better w/o ToList 
    .Where(docu => !docu["_id"].IsObjectId) 
    .Max(docu => docu["_id"].ToInt64()); 
+0

getChannelNames atm возвращает список строк. Должен ли я изменить метод для возврата чего-то еще? –

+0

Он должен работать со строкой просто справа выберите Select и SelectMany, чтобы преобразовать ваши входные данные в любой тип, который вы возвращаете в лямбда-функции. Поэтому, когда первый SelectMany выполняется, у вас будет коллекция имен каналов (строки, которые, как я предполагаю). Вторая будет возвращать коллекцию BsonDocuments. Где будет работать с этими документами и Max вычисляет максимальное значение идентификатора документа. Для этого может потребоваться некоторая кастинг или ToArray, ToList, но идея такая же. –

+0

Просто для объяснения wh Я сделал это. Я использовал SelectMany, где вы использовали foreach + Add для распаковки коллекции напрямую, а затем используйте эту коллекцию для передачи данных в следующий запрос. –