
Ilya
12.04.2018
07:04:30
Всем добрый день, подскажите с таким вопросом:
Есть документ вида:
{
_id: ObjectID
name: string
....,
items: [
{
name: string
type: string
size: int
},
...
]
}
как видно у него есть массив вложенных документов items, в нем могут быть несколько тысяч.
как при выборке ограничить элементы в items?
на сайте монги советуют использовать аггрегации, но с ними проблема начинается в том что необходимо испольховать skip и limit, и в этом случае запрос начинает работать очень медленно

Javed
12.04.2018
07:07:35

Ilya
12.04.2018
07:07:54
в смысле вынести в коллекцию отдельную?

Javed
12.04.2018
07:08:49
Ну да, где он имеет ещё одну поля создателя и хранить там ай ди его

Google

Javed
12.04.2018
07:09:03
Я не спец, тоже учусь

Yurii
12.04.2018
07:10:45

Ilya
12.04.2018
07:10:56
да пагинацию

Yurii
12.04.2018
07:11:52
да пагинацию
и ты делаешь {$unwind: "items"}, а потом $skip и $limit?

Ilya
12.04.2018
07:13:34
нет $unwind не пробывал, если его сделать и отфильровать то в результате будут только те items которые попали в условие?

Yurii
12.04.2018
07:16:05
ну понятно, что skip и limit это уже твои настройки пагинации

Ilya
12.04.2018
07:17:45
эээ дак что в этом случае дал unwind ?

Yurii
12.04.2018
07:18:57

Ilya
12.04.2018
07:19:46
я наверно плохо сформулировал
есть документ у которого в items тысячи вложенных документов,
мне надо вывести этот же документ но с чтобы в items остались только те корые удовлетворяют условию

Yurii
12.04.2018
07:22:42
тогда вместо $unwind - https://docs.mongodb.com/manual/reference/operator/aggregation/slice/

Google

Ilya
12.04.2018
07:25:04
nак пагинация и items никак не связанны - пагинация для документа всего а не для items,
items надо по фильтру отфитровать а не по кол-ву

Yurii
12.04.2018
07:25:57
ну тут ты сказал, что надо именно пагинацию ?
тебе надо пагинацию, что ты skip и limit используешь, или просто последние несколько штук?
да пагинацию

Ilya
12.04.2018
07:26:13
пагинацию для всего документа
я не говорил что для items

Yurii
12.04.2018
07:26:44
ну вопрос же был как раз за items
ладно, проехали
возвращайся тогда сюда:
db.collection.aggregate([
{$match: some_criteria },
{$skip: skip_qty },
{$limit: limit_qty }
{$project: {
items: {$filter: {
input: "$items"
as: "item",
cond: { do_some_cond_with_$$item }
}},
project_all_need_fileds: 1
}}
])
https://docs.mongodb.com/manual/reference/operator/aggregation/filter/
в таком случае ты делаешь сначала пагинацию по документах, а потом фильтруешь внутринности items по переденным критериям

Ilya
12.04.2018
07:33:15
ок, спасибо сейчас попробую
в общем работает, но опять та же самая проблема как только добавляешь skip - сразу скорость запроса проседает =(

Dmitry
12.04.2018
08:15:42
Со скипом всегда проседает. Это инородное понятие для NoSQL. Индексы сделаны?
В теории если зададите критерии - скорость будет выше.
Т.е. если у вас есть итерационное или предсказуемое поле его можно сформировать и скорость вывода уведичится

Ilya
12.04.2018
08:19:07

Dmitry
12.04.2018
08:20:31
Да. Всегда. Для моего скип - это инородное. Она сначала делает агрегацию, а потом ее пагинирует. А вот если в условия пгрегации засунуть к примеру инкриментальный ид - будет значительно быстрее. Тогда агрегация будет скажем с 0 до 10
* монги / мое го
Вообще готовые агрегации со скипом ведь тоже можно индексировать и хранить

Google

Dmitry
12.04.2018
08:21:55
Или кешировать редисом
Забудьте все что знали о реляции) агрегация - берет всегда весь массив документов. Дополнительная выборка - всегда + 1 операция

Ilya
12.04.2018
08:24:51
ну вообще мне просто не понятно было почему project вобычном find не может нормально отфильтровать подмассив документов
в find же скип быстро работает)

Yurii
12.04.2018
08:25:24
https://dzone.com/articles/fast-paging-with-mongodb
один из вариантов сделать быстрее скип -
.find({'_id'> last_id})

Dmitry
12.04.2018
08:25:47

Ilya
12.04.2018
08:28:52

yopp
12.04.2018
08:31:37
Если вы хотите skip/limit по вложенным документам с условием по вложенным документам — быстро не будет.

Dmitry
12.04.2018
08:32:59

Ilya
12.04.2018
08:33:29

yopp
12.04.2018
08:33:50

Dmitry
12.04.2018
08:35:20

Peter
12.04.2018
08:35:58
Вопросик, возможно ли в Studio3t посмотреть реальное время выполнение агрегатки? Или в каком GUI это реально?

yopp
12.04.2018
08:35:58
Документ это сериализированные в BSON данные. Самый простой способ смотреть на документ как на хэш таблицу
Поддокумент это просто ключ значением которого является ещё один хеш
Или массив таких хэшей
Так как BSON массив это тоже документ, у которого ключ эквивалентен индексу элемента

Google

Nick
12.04.2018
08:38:04

yopp
12.04.2018
08:38:19

Peter
12.04.2018
08:39:16
explain?
В Studio3t он не возвращает время выполнение

Ilya
12.04.2018
08:40:14
Тогда полностью сформулируйте задачу
Есть документы такие:
{
_id: ObjectID
name: '1'
items: [
{
name: 'cвойство1'
type: 'тип1'
size: 10
},
{
name: 'cвойство2'
type: 'тип2'
size: 20
},
{
name: 'cвойство3'
type: 'тип2'
size: 0
},
]
},
....,
{
_id: ObjectID
name: '2'
items: [
{
name: 'cвойство1'
type: 'тип1'
size: 110
},
{
name: 'cвойство2'
type: 'тип2'
size: 120
},
{
name: 'cвойство3'
type: 'тип2'
size: 10
},
]
}
Надо сделать запрос такой чтобы вытащить документы у кторых имя может быть одно из '1', '2', '10', и в items у них есть поддокументы у которых size > 10
Причем в ответе для найденных документов не надо выводить поддокументы которые условию size > 10 не удовлетворяют.
причему еще надо делать пагинацию

Admin
ERROR: S client not available

yopp
12.04.2018
08:42:43
Если вам на страницу нужно вывести фиксированное количество поддокументов, то как я уже сказал — быстро не будет.
Если нужно вывести фиксированное количество документов, то skip/limit

Nick
12.04.2018
08:43:08
Есть документы такие:
{
_id: ObjectID
name: '1'
items: [
{
name: 'cвойство1'
type: 'тип1'
size: 10
},
{
name: 'cвойство2'
type: 'тип2'
size: 20
},
{
name: 'cвойство3'
type: 'тип2'
size: 0
},
]
},
....,
{
_id: ObjectID
name: '2'
items: [
{
name: 'cвойство1'
type: 'тип1'
size: 110
},
{
name: 'cвойство2'
type: 'тип2'
size: 120
},
{
name: 'cвойство3'
type: 'тип2'
size: 10
},
]
}
Надо сделать запрос такой чтобы вытащить документы у кторых имя может быть одно из '1', '2', '10', и в items у них есть поддокументы у которых size > 10
Причем в ответе для найденных документов не надо выводить поддокументы которые условию size > 10 не удовлетворяют.
$elementMatch

yopp
12.04.2018
08:43:44
А, да. Для фильтра по вложенным документам, да

Ilya
12.04.2018
08:43:49
2 надо вывсети фиксированное кол-во документов, но если применять skip в агрегациях запрос начинает значительно
угу
ой

Nick
12.04.2018
08:44:33
так в первом match в аггрегате указываете запрос с elementMatch и вашим услвоием по имени, а дальше как и выше unwind-match-group
и поверх skip-limit

Ilya
12.04.2018
08:45:28
да все правильно, просто если без скипа делать запрос то он несколько милисекунд а со скипом уже полсекунды

Nick
12.04.2018
08:46:14
если хотите быстро, от меняйте структуру данных так чтобы было просто их получать
иначе всегда будет медленно

yopp
12.04.2018
08:46:51
Я не очень понимаю в чем загвоздка

Google

yopp
12.04.2018
08:47:12
Если нужно выводить например 10 документов в которых есть хоть одно совпадение с поддокументом — это простая задача

Ilya
12.04.2018
08:47:31
ну я думаю что полсекунды на запрос - это проблема?

yopp
12.04.2018
08:48:18
Посмотрите в explain

Nick
12.04.2018
08:48:20

yopp
12.04.2018
08:48:39
Вероятно вам нужно сделать индекс по полю вложенного документа
В вашем случае по items.size

Ilya
12.04.2018
08:49:23
разве на скип как то повлияет создание индекса?

Nick
12.04.2018
08:49:26
кстати аггрегаты в 3.6 только ан первый match индекс юзают?

yopp
12.04.2018
08:49:45

Nick
12.04.2018
08:50:16
чет затупил, задача же позволяет сделать skip-limit сразу после первого матч
а уже после делать анвинды

yopp
12.04.2018
08:50:32

Nick
12.04.2018
08:50:37
ну да
хотя стой

Ilya
12.04.2018
08:50:46
смотрите я могу выбрать без скипа 1000 элементов за 10 мс, а допустим выбрать 10 документов со скипом в 1000 займет уже полсекунды - это нормально поведение*?

Nick
12.04.2018
08:51:07
он просил чтобы те элементы массива у которых size>10 не выводились

yopp
12.04.2018
08:52:08