Как найти наибольшее число путем сортировки внутри буквенно-цифровой строки в MongoDB - PullRequest
1 голос
/ 29 января 2020

Я хотел бы получить наибольшее число внутри этих буквенно-цифровых строк:

    [
{
    "LsNr": "L9"        
},
{
    "LsNr": "L99"
},
{
    "LsNr": "L100"
}
    ]

Однако MongoDB возвращает L9 как наибольшее число в моем методе C#:

        public string MaxLsNr<T>(string cl, string prefix) //collection and prefix 'L'
        {
            string bsonQuery = "{'LsNr': {$regex: '" + prefix + "'}}"; //filter by prefix
            var filter = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(bsonQuery);

            var collection = db.GetCollection<BsonDocument>(cl);

            //returns `L9` instead of `L100`
            var result = collection.Find(filter).Sort("{LsNr: -1}").Limit(1).ToList();
            //some more code
        }

Как обойти это? Вам не нужно отвечать C# по теме. Это нормально для меня, если вы объясните возможные варианты (без изменения существующих пар ключ-значение) или непосредственно запрос MongoDB (предпочтительно).

Ответы [ 2 ]

1 голос
/ 29 января 2020

Это из-за сравнения строк MongoDB, если я не ошибаюсь, вы можете получить этот заказ "L99" > "L9" > "L100", потому что он будет проверять букву за буквой в данной строке, так как L совпадает во всех документах, тогда это будет go для следующего письма, таким образом, вы получите указанный выше порядок.

1) Если все документы имеют LsNr , начинается с L , попробуйте это:

Запрос:

collection.aggregate([
/** $match similar to .find() */
{ $match: { filter } },
/** $addFields to add a new field 'number' which bring number out of 'L9' -> 9 */
{ $addFields: { number: { $toInt: { $substr: ["$LsNr", 1, -1] } } } },
/** sort number & $project to remove newly created field 'number' */
{ $sort: { number: -1 } }, { $project: { number: 0 } }, {$limit: 1}
])

Тест: MongoDB-Playground

2) Остальные документы имеют LsNr начинается с разных букв, попробуйте это:

Запрос:

collection.aggregate([
    { $match: { filter } }, // Your filter
    { $addFields: { letter: { $substr: ["$LsNr", 0, 1] }, number: { $toInt: { $substr: ["$LsNr", 1, -1] } } } },
    { $sort: { number: -1 } }, { $sort: { letter: -1 } },
    { $project: { letter: 0, number: 0 } }])

Тест: MongoDB-Playground

Вы можете использовать агрегацию для достижения того, что нужно - что-то вроде .find(). Так как у вас есть фильтр, используйте его на первом этапе $match, чтобы сделать ваш набор данных меньше для дальнейших этапов, в любом случае, пожалуйста, укажите индекс в поле LsNr.

0 голосов
/ 29 января 2020

Поскольку вы сортируете строки, сравнение будет основываться на каждой букве, начинающейся слева.

Предложение

  • Получить данные из коллекции на основе в вашем фильтре
  • найдите максимальное число (без префикса)
  • используйте это максимальное число, чтобы получить первую соответствующую запись (что всегда будет так)

Это будет подключаться к mongoDb только один раз. Поскольку все данные были получены на основе вашего основного фильтра, это всего лишь манипулирование данными на местном уровне.

using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using System.Linq;

public string MaxLsNr<T>(string cl, string prefix) //collection and prefix 'L'
{
    string bsonQuery = "{'LsNr': {$regex: '" + prefix + "'}}"; //filter by prefix
    var filter = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(bsonQuery);

    var collection = db.GetCollection<BsonDocument>(cl);

    var data = collection.Find(filter).ToList();

    // Get the max number from the results.
    int max = data.Max(x => int.Parse(x["LsNr"].ToString().Substring(1)));

    // Get the single record based on Prefix and Max number.
    var result = data.FirstOrDefault(x => x["LsNr"].Equals($"{prefix}{max}");

    // other code here...
}
...