Сценарий оболочки агрегации MongoDB для драйвера MongoC#

Как я могу преобразовать этот сценарий Mongo Shell в драйвер MongoDB С#?

var myItems = []

var myCursor = db.Tickets.aggregate(
   [
      { $match : { TicketProjectID : 49 } },
      { $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } }
    // I will have a list of fields that I need to concatenate at run time. So C# query should support concatenation for "N" number of fields at run-time.
      //{ $group: { _id: null, count: { $sum: 1 } } }

   ],
      { allowDiskUse: true }
)

   //This seems like a ugly performance approach when we are working against 100k results with above match
     while (myCursor.hasNext()) {
         var item = myCursor.next();
         if(item.concatValue.search(/mysearchkey/i) > -1)
             {
                myItems.push(item.TicketID)
             }
    }    
    myItems

или есть лучший способ выполнить поиск строки в конкатенированной проекции вместо foreach в курсоре, так как некоторые запросы могут получить 50 тыс. записей.

Это то, что я пробовал до сих пор (без использования агрегации)

Примечание. Этот код урезан для общедоступных сайтов вопросов и ответов. Поэтому, пожалуйста, считайте это псевдокодом

 var tickets = ticketsCollection.FindSync(filter).ToList();
                string concatinatedValue = string.Empty;
                foreach (var ticket in tickets)
                {
                    foreach (var field in customFieldsForThisProject)
                        concatinatedValue += ticket[field.Replace(" ", "_")];

                  if(concatinatedValue.StripHtml().contains("MysearchWord"))
                 {
                   TikectIdList.Add(ticket["TicketID"])
                 }
                }

person HaBo    schedule 09.06.2016    source источник
comment
@KDecker обновил вопрос тем, что я пробовал. Я не пытался использовать агрегацию с драйвером С#.   -  person HaBo    schedule 09.06.2016


Ответы (2)


Отредактировано в соответствии с данным комментарием

Если вы можете использовать AsQueryable(), вы можете получить такие значения:

var dbResult = from ticket in ticketsCollection.AsQueryable()
               where ticket.TicketProjectID == 49
               select new 
               {
                   TicketProjectID = ticket.TicketProjectID,
                   TicketID = ticket.TicketID,
                   ConcatValue = ticket.Status + " - " + ticket.Name
               };

и чем позже вы можете сделать что-то вроде этого:

var result = from dbr in dbResult
             where dbr.ConcatValue.Contains("something") //or
             where dbr.ConcatValue.StartsWith("something")//or you can use regex
             select dbr;

Примечание. По какой-то причине свойства Status и Name из типа Ticket должны иметь тип String для работы конкатенации, поскольку драйвер mongo не распознает вызов ToString() из какого-либо другого типа.

Если вы хотите объединить свойства некоторых других типов, вы можете получить их отдельно от базы данных, а затем объединить их локально.

note, i'm not that good with mongo shell i could mess something up but you can see in which way you could go

В качестве альтернативы вы можете написать свою команду оболочки следующим образом и поместить ее в строку:

var command = @"db.Tickets.aggregate(
[
    { $project: { TicketProjectID:1, TicketID:1, concatValue: { $concat: [ "$Status", " - ", "$Name" ] } } },
    { $match : { TicketProjectId : 49, concatValue : { $regex : /mysearchkey/i } } }
],
{ allowDiskUse : true }
);";

затем выполните его в С# с помощью метода RunCommandAsync из MongoDatabase.

var result = await mongoDatabase.RunCommandAsync<BsonDocument>(BsonDocument.Parse(command));
person Nikola.Lukovic    schedule 13.06.2016
comment
TicketProjectID = 1 указывает, что это поле должно быть включено в результат, а остальные проигнорированы. - person HaBo; 13.06.2016
comment
Мне нужна эта динамика, ticket.Status + - + ticket.Name. У меня будет список полей, которые мне нужно объединить, так как я могу создать эту конкатенацию во время выполнения? - person HaBo; 13.06.2016
comment
тогда я думаю, что ваше текущее решение - это то, что вы получаете, если у вас нет возможности ввести что-то вроде LinqToQueryString между вашим запросом и драйвером mongodb - person Nikola.Lukovic; 13.06.2016
comment
я могу выполнить сценарий оболочки как есть из C #? - person HaBo; 13.06.2016
comment
я отредактировал ответ, может быть, вы могли бы попробовать что-то подобное - person Nikola.Lukovic; 13.06.2016
comment
команда недействительна JSON для передачи в RunCommand, она не может начинаться с db.Tickets - person HaBo; 20.06.2016
comment
Пришлось внести еще некоторые изменения, но, наконец, смог получить то, что мне нужно - person HaBo; 20.06.2016

Благодаря @Nikola.Lukovic, работающему над его псевдокодом, я придумал это рабочее решение.

Первый подход: полное использование драйвера C#

var ticketsCollection = _mongoConnect.Database.GetCollection<BsonDocument>("Tickets");

            var dbResult = from ticket in ticketsCollection.AsQueryable()
                select new
                {
                    TicketProjectID = ticket["TicketProjectID"],
                    TicketID = ticket["TicketID"],
                    ConcatValue = ticket["Status"] + (string) ticket["Name"]
                };
            var matches = from dbr in dbResult
                where dbr.ConcatValue.Contains(searchKey)
                where dbr.ConcatValue.StartsWith(searchKey)
                select dbr;

Это не будет работать для моего сценария, поскольку поля, которые я пытаюсь объединить, представляют собой строку типа, но $add будет работать только с типами numeric и date.

Подход второй: использование RunCommand и передача прямой команды Shell. Это будет работать для всех типов данных. И работает для моих нужд.

        var projectCommand =
            BsonDocument.Parse(
                "{ $project: { _id: -1, TicketProjectID:1, TicketID:1, concatValue: { $concat: [ \"$Status\", \" - \", \"$Name\" ] } } }");
        var matchCommand =
            BsonDocument.Parse("{ $match: {concatValue: { $regex: '" + searchKey + "', $options: 'i'} } }");

        var pipeline = new[] {projectCommand, matchCommand};
        var result = ticketsCollection.Aggregate<BsonDocument>(pipeline).ToList();
        if (result.Count > 0)
            return result.Select(x => (int)x["TicketID"]).ToList();
        return null;
person HaBo    schedule 20.06.2016