LINUX.ORG.RU

Узнать сколько бутылок пива в магазине

 ,


0

1
Schema {
   shopName: String,
   beers: [{brand: String, vol: Number, alc: Number}]
}

model = new Schema();
model.findOne().countXXX



Нужно узнать сколько бутылок пива (countXXX) в магазинах, не вытаскивая все ящики

★★★★

Последнее исправление: gobot (всего исправлений: 1)

Не совсем понял что значит не вытаскивать все ящики. Тот же aggregate все равно читает этикетки на бутылках:

db.collection.aggregate([
  {
    $unwind: "$beers"
  },
  {
    $match: {
      "beers.brand": "Балтика9"
    }
  },
  {
    $group: {
      _id: null,
      count: {
        $sum: "$beers.count"
      }
    }
  }
])

Если под countXXX вы подразумеваете db.collection.countDocuments() то это буквально обертка, внутри которой тот же самый aggregate:

db.collection.aggregate([
   { $match: <query> },
   { $group: { _id: null, n: { $sum: 1 } } }
])
Obezyan
()

По простому никак.

Если очевидного индекса по магазу и/или бренду (+ запроса агрегатора) недостаточно, нужно делать свой materialized view и обновлять его периодически либо делать свой aggregate запрос c $merge. Можно навернуть дополнительный слой кеша, прямо в монге или соседнем редисе (ну мы же модную распределенную систему делаем, а чо). Но вообще монга старается кешировать результаты запросов, если они достаточно частые.

Если вопрос не из праздного любопытства, добавь больше информации: сколько данных, насколько большие группы, какой паттерн доступа к данным, и что ты вообще уже напрофилировал.

anonymous
()
Ответ на: комментарий от anonymous

Тут скорее стоит начать с вопроса «почему mongodb»? Такие данные просто идеальны для хранения в реляционной БД в третьей нормальной форме с индексацией и получением агрегированных данных с помощью реляционной алгебры. Одно удовольствие же с ними так работать, а не вот это вот все.

Obezyan
()
Ответ на: комментарий от Obezyan

У тебя должны быть очень веские причины, чтобы сегодня выбрать что-то отличное от постгреса. Этот дефолт легко отмасштабировать (если надо конечно) до огромных объемов и трафика. Встроенный json добавляет поддержку «документов».

Но, у ТС монга, и кто я такой, чтобы говорить ему все переделывать.

anonymous
()
Ответ на: комментарий от anonymous

Ну как то странно, срез можно сделать, вернуть частичный список

findOne().slice("beers", [0, 10])


А тупо подсчитать и вернуть количество нет? Мне данные если не нужны.

gobot ★★★★
() автор топика
Ответ на: комментарий от ya-betmen

Отдельную сущность заводить и обновлять ее при каждом добавлении? Мне кажется должно быть просто и очевидно, сделал выборку документов, в каждом из них есть массив, почему нельзя вернуть просто его размер? Размер массива же где то в бинарном виде хранится, тупо счетчик 1 байт, его же не нужно считать, обходя все элементы через for. Просто не могу понять почему нет простого решения без aggregate. Slice есть, а size нет.

gobot ★★★★
() автор топика
Ответ на: комментарий от gobot

Так тебе вроде все комментаторы выше сказали что задача говно и проектировщик - мудак.

Там же и правда нужен постгрес + разработчик уровня 60к рублей в месяц. А ты там кстати чем занимаешься? Не оч понятно.

anonymous
()
Ответ на: комментарий от gobot

Я как понимаю без этой уродливой конструкции с aggregate никак по другому?

Никак, это подход mongodb к получению агрегированных данных. А уродливо это все выглядит потому что для этих данных mongodb не очень подходит.

Мне то желательно документы получить в итоге

Причем тут документы? Вы написали «Нужно узнать сколько бутылок пива». Это число, а не коллекция документов где есть бутылки указанного бренда.

Obezyan
()
Ответ на: комментарий от gobot

Мне то желательно документы получить в итоге

Ну так и создай этот документ и считай бутылки в нем ручками. Вы хотели NoSQL, вы ее получили.

anonymous
()
Ответ на: комментарий от Obezyan

Причем тут документы? Вы написали «Нужно узнать сколько бутылок пива». Это число, а не коллекция документов где есть бутылки указанного бренда.

К каждому документу цеплять поле countBottle... хотя... я начинаю понимать в чем причина, в некотором дизайне, либо документ получай, либо произвольные данные aggregate,а микшировать никак нет

уродливо это все выглядит потому что для этих данных mongodb не очень подходит

ойй да ладно, подходит не подходит

*** MongoDB подходит для следующих применений: ***

регистрация и хранение информации о событиях;
системы управления документами и контентом;
электронная коммерция;
игры;
данные мониторинга, датчиков;
мобильные приложения;
хранилище операционных данных веб-страниц (например, хранение комментариев, рейтингов, профилей пользователей, сеансы пользователей)

gobot ★★★★
() автор топика
Ответ на: комментарий от ya-betmen

Просто select count

просто? Из 2 таблиц данные же будут. select *, (select count from beers where show_id = s_id) as countB from shops

А в монго в 1 документе. Проблем по сути нет, если вытащить все эти бутылки и локально подсчитать array.length, но зачем мне их вытаскивать, если я с этими данными работать сейчас не буду. Собственно мне нужно сделать проверку перед добавлением бутылки в магазин. Если бутылок больше 10, то выгнать поставщика, ибо нет места в магазине.

Просто я не пойму почему бл такое через aggregate только делается! Западло мне так делать. Хочу в документ добавить «инородное поле»

ЗЫ. Есть там $push {$slice}... Но это truncate, старые бутылки будут потеряны, но магаз не переполнится... Но хочется проверку хотя бы перез $push

gobot ★★★★
() автор топика
Последнее исправление: gobot (всего исправлений: 1)

Ладно я спать, завтра продолжим. Пишите пока все решения, которые мне подойдут по проверке бутылок перед добавлением. Если > 10, то не добавлять и дать пинка поставщику который их принес. НО, не вытаскивая все бутылки. $push {$slice} не предлагать

gobot ★★★★
() автор топика
Ответ на: комментарий от gobot

Просто я не пойму почему бл такое через aggregate только делается! Западло мне так делать. Хочу в документ добавить «инородное поле»

Так aggregate это база. Запросов в mongoDB, куча функций буквально обертки над ним.

Мало того что вы используете не правильный инструмент для задачи (допустим, так исторически сложилось до вас), но вы еще и воротите нос от правильного использования этого инструмента. Стреляете себе не только в правую но и левую ногу так сказать. Вы эникейщик самого низкого пошиба, фу таким быть.

Obezyan
()
Ответ на: комментарий от Obezyan

Так aggregate это база

Хорошо. Учту

используете не правильный инструмент для задачи

А ты что задачу знаешь что-ли? Чем задача с магазином не годна для монги, объясни? Мне кажется это самое примитивный пример, такими все форумы завалены - это стандартная схема - документ - в нем массивы. Что, все дураки, используют монгу не правильно или че?

воротите нос

о боже, где я ворочу нос? Я тебе чем-то обязан?

Вы эникейщик самого низкого пошиба, фу таким быть

О боже, ну хорошо, считай что ты меня унизил и самоутвердился. Ты крутой! Ты бох и гуру вселенного масштаба!

gobot ★★★★
() автор топика
Ответ на: комментарий от gobot

Размер массива же где то в бинарном виде хранится, тупо счетчик 1 байт, его же не нужно считать, обходя все элементы через for

Почему ты решил, что aggregate обходит их через for?

а size нет.

Есть $size. Но тоже через aggregate. ЯННП чем ты недоволен, такой вот синтаксис запросов, тот же select count вид сбоку.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Почему ты решил, что aggregate обходит их через for?

Да я ничего не решил, просто предположение, почему нельзя выдать size БЕЗ aggregate... ну это так просто!

Есть $size. Но тоже через aggregate. ЯННП чем ты недоволен, такой вот синтаксис запросов, тот же select count вид сбоку.

да с aggregate понятно что можно ВСЕ, но там есть существенный минус, результат выдачи простой JSON, ка я использую mongoose со всякими validate, transform, virtuals ну короче модели не цепляются

gobot ★★★★
() автор топика
Ответ на: комментарий от no-such-file

Так ты aggregate сразу с $cond if $size<=10 then $push делай и не страдай хернёй

Нууу...да... Короче все в aggregate упирается. Почему в обычном find() нельзя использовать $size, а в aggregate можно? Тут писали что якобы все это обертки над aggregate, но эти обертки компактные и удобные. Какая-то нестыковка есть, либо с mongoose либо с mongo, либо у меня в голове ))

gobot ★★★★
() автор топика
Ответ на: комментарий от no-such-file

И кстати пока не забыл, может знаешь почему нельзя такое


users = {
   alias: String,
   ignors: [{uid: Number}]
   room: {
      type: String,
      name: String,
      createdAt: Date,
      friends: [{
         uid: Number
      }]
   }
}

db.users.find({
    alias: "vasya"
}, {
    "room.friends": {
        $elemMatch: {
            uid: "3453432654675"
        }
    }
})

Query failed with error code 31275 with name 'Location31275' and error message 'Cannot use $elemMatch projection on a nested field.' on server localhost:27017


А если просто ignors: {$elemMatch: {}} то можно. Тоже какая то тупость?

gobot ★★★★
() автор топика
Последнее исправление: gobot (всего исправлений: 3)
Ответ на: комментарий от no-such-file

С aggregate кстати не понял как push с условием делать, но нашел более лаконичный способ

Но размер массива в projection никак походу не получить...
пока использую такой костыль, чтобы по максимуму сократить возвращаемые данные от сервера


/***

GNU GPL 1/0/0/0/0

***/

User  = {
  name: String,
  email: String,
  //...
  friends: [
     {
       uid: ObjectID,
       notify: Boolean,
       createdAt: Date,
       approvedAt: Date,       
     }
  ]
}

const user = await db.user.findOne({
   _id: req.session.uid
}, {
    "friends._id": 1
}).orFail(new Error("Вы не авторизованы!"))


if(user.friends.length > 10) throw new Error("Много друзей!")


await db.user.updateOne({
    _id: id,
    "friends.uid": {$ne: uid}
}, {
    $push: {
        "friends": {
            uid: req.body.uid
        }
    }
})

res.send("Урааааа!")

gobot ★★★★
() автор топика