Cosmos DB - частичное сопоставление объектов с помощью IDocumentQuery - PullRequest
0 голосов
/ 03 августа 2020

Мы используем Azure Cosmos DB и используем пакет nuGet microsoft. azure .documentdb.core для отправки к нему запросов. Это хорошо работает для большинства наших запросов, но теперь у нас есть запрос, который нам трудно перевести.

Предположим, что этот простой тип объекта:

{ type: "abc",
  flags: [
     { feature: "x", scope: "user", value: "on" },
     { feature: "y", scope: "global", value: "off" }
  ]
}

Теперь допустим, что мы хотим получить все эти объекты, соответствующие некоторой функции и области действия, но полностью игнорируя значение.

Это можно сделать с помощью следующего запроса:

SELECT * FROM MyCollection c WHERE /*other filters*/ and ARRAY_CONTAINS(c.flags, { feature: 'x', scope: 'user' }, true)

Когда я пытаюсь сопоставить это с C# Я получаю это:

public class Flag {
   public string feature { get; set; }
   public string scope { get; set; }
   public string value { get; set; }
}

public class MyRecRepo {
   public async ICollection<MyRecType> GetRecordsWithFlag(Flag: flag) {

      var request = client
         .CreateDocumentQuery(collection, feedoptions)
         .Where(rec => /*other filters*/ && rec.flags.Contains(flagFilter));

      return await request
         .AsDocumentQuery()
         .ExecuteNextAsync<MyRecTyp>();
   }
}

//called like this:
var flagFilter = new Flag { feature = "x", scope = "user" };
var list = await repo.GetRecordsWithFlag(flagFilter);

PS: Я хочу использовать тот же код для получения любой комбинации фильтров флагов. Итак, отфильтруйте флаги, которые имеют только «feature: x», или записи, которые имеют функцию «y» и значение «on» ... Итак, я думаю, что мог бы создать один класс для каждой комбинации свойств, но похоже, что это много работы конечно, если реальный живой код действительно имеет больше свойств.

PS: Я знаю, что код примера не будет компилироваться, это псевдокод, чтобы сделать его немного более читаемым.

1 Ответ

0 голосов
/ 11 августа 2020

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

  1. Создайте запрос SQL самостоятельно. Вы можете использовать отражение до go через свойства в вашем объекте Flag и использовать только те, которые установлены.

  2. Use Any (). Вместо SELECT r FROM r WHERE ARRAY_CONTAINS(r.property1, “{‘name1’: ‘value1’}”, true) Any () оценивает SELECT r FROM r WHERE EXISTS(SELECT p FROM p IN r.property1 WHERE p.name1 = ‘value1’).

    На этом этапе вам все еще нужно решить проблему просмотра только определенных свойств c. Вы можете изменить это, передав свое выражение напрямую вместо объекта. Метод становится GetRecordsWithFlag(Expression<Func<MyRecType, bool>> expression), а вызов repo.GetRecordsWithFlag(d => /*{other filters} */ && d.flags.Any(f => f.feature == "y" && f.value == "on"))'

    Причиной беспорядка в этом методе является то, что вы заметите, что мне пришлось включить все фильтры в вызов метода. Вы можете использовать Expression.AndAlso(), чтобы комбинировать фильтры флагов с теми, которые вы в настоящее время устанавливаете в методе репо, но существует проблема с вложенными фильтрами в предложениях WHERE, из-за которой это приводит к недопустимому запросу. Команда знает об этом, но это одна из зависимостей, поэтому решить эту задачу непросто.

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