JSdata - запрос на совпадение всех элементов в массиве (ключевое слово MongoDB '$all')
Я использую jsdata для создания локального кэша для веб-приложения Angular 1.5. Я смоделировал свои данные с соответствующими отношениями, и все работает отлично. Я борюсь с запросом, и я даже не уверен, будет ли это вообще работать с js-данными:
Предположим, у меня есть коллекция тегов с идентификатором и именем
[
{
"id": 1,
"name": "Tag 1"
},
{
"id": 2,
"name": "Tag 2"
}
,
{
"id": 3,
"name": "Tag 3"
}
]
и некоторые посты, где были назначены теги:
[ {
"id": 1,
"name": "Post with tags 1 and 2",
"tags": [1, 2]
},
{
"id": 2,
"name": "Post with tags 2 and 3",
"tags": [2,3]
},
{
"id": 3,
"name": "Post with tag 3",
"tags": [3]
}
]
Затем я определяю Tag и Post Datastore и устанавливаю отношение hasMany к сообщениям:
relations: {
hasMany: {
tag: {
localField: 'embedded_tags',
localKeys: 'tags'
}
}
Когда я запрашиваю сообщения, я вижу, что мои теги появляются во встроенных тегах, так что это нормально. Теперь я хотел бы отфильтровать свои посты по определенному набору тегов: допустим, я хочу видеть только посты с тегами 2 и 3, то есть пост 2.
Очевидно, это не работает
var resultISect = postDS.filter({
where: {
'tags': {
'iSectNotEmpty': [1, 2]
}
}
})
Также это не так (и, конечно, выдает предупреждение о дублировании ключа):
var resultAnd = postDS.filter({
where: {
'tags': {
'contains': 3,
'contains': 2
}
}
})
В MongoDB / Mongoose есть ключевое слово $all, которое делает именно это. Есть ли способ иметь такую фильтрацию в jsData или это слишком сложная задача для базы данных, и ее следует выполнять на бэкэнде - чего я хотел бы избежать, потому что это более или менее весь смысл в наличии копии локального кэша, право?
2 ответа
'where' может быть массивом, это должно работать:
where: [
{
tags: {
contains: 3
}
},
'and'
{
tags: {
contains: 2
}
}
]
Взяты отсюда: https://github.com/js-data/js-data/blob/c3fcde1abab910cdf4d39e3fbc42699a3b27c1da/test/unit/query/filter.test.js#L243 (хорошее место, чтобы узнать все функции фильтра, кстати)
Я добавил функцию 'matchAll' в js-data _utils2.default
, Пока это работает, может быть, это кому-то поможет.
Добавьте эту функцию рядом с функцией пересечения:
// check if array contains all elements queried
function matchAll(arr, elements) {
if (!arr || !elements) {
return true;
}
for (var i = 0, length = elements.length; i < length; i++) {
if (contains(arr, elements[i])) {
continue;
} else {
return false;
}
}
return true;
}
Выставьте эту функцию вместе с другими:
exports.default = {
...
guid: guid,
intersection: intersection,
matchAll: matchAll,
isArray: isArray,
isBlacklisted: isBlacklisted,
...
}
и заставить его реагировать на новое ключевое слово:
...
} else if (op === 'isectEmpty') {
expr = !_utils2.default.intersection(val || [], term || []).length;
} else if (op === 'isectNotEmpty') {
expr = _utils2.default.intersection(val || [], term || []).length;
} else if (op === 'matchAll') {
expr = _utils2.default.matchAll(val || [], term || []);
} else if (op === 'in') {
...