Задать вопрос
  • Есть ли какой-то инструмент выполнения запросов в базу данных с отсрочкой?

    @foterio
    Просто пихайте все в очередь. Затем два пути:
    1. Опрашиваем по таймеру. Каждые пять минут consumer подключается к очереди забирает все, что там есть и затем сохраняет в базу весь этот batch.
    2. Consumer берет из очереди по N сообщений, и вставляет в базу batch.

    И там и там есть гибкость. Сегодня каждые пять минут, а в вечер пятницы-субботы, когда условно нагрузки выше (HoReCa, Delivery-сегмент и прочее), можно изменить на каждые три минуты. Тоже самое и по сообщениям. Сегодня N = 10, а завтра N = 50.
    Ответ написан
    Комментировать
  • Как лучше хранить денежные суммы в Postgres?

    @foterio
    Несколько лет назад, я потратил неделю чтобы гарантировано разобраться и принять правильное решение как хранить деньги в Postrgres.
    3 вариант оказался единственно верным. Хранить деньги нужно в копейках, центах в виде int. Операции сложения вычитания так же необходимо проводить в копейках, центах. И только при выводе денег для конечного пользователя вы приводите его в читабельный вид $10.99
    Ответ написан
    2 комментария
  • Есть ли бесплатное API для получения всех улиц и домов конкретного города?

    @foterio
    Заходим на https://overpass-turbo.eu/
    Город необходимо писать на Английском
    [out:json][timeout:25];
    // fetch area “Samara” to search in
    {{geocodeArea:Samara}}->.searchArea;
    (
      node["addr:housenumber"](area.searchArea);
      way["addr:housenumber"](area.searchArea);
      relation["addr:housenumber"](area.searchArea);
    );
    out body;
    >;
    out skel qt;

    После того, как запрос обработается, нажимаем экспорт и выбираем нужный нам форматы:
    GeoJSON, GPX, KML, сырой OSM

    Я обычно работают с GeoJSON. Там вы получите все дома с улицами (и 5% всякого непонятного шлака или дублей). Шлак необходимо будет отфильтровать, там уже по месту разберетесь. Весить будет от 9 до 20 мегабайт.
    Спорные моменты придется перепроверять через геокодинг яндекса.
    Ответ написан
    Комментировать
  • Добавление нескольких валют?

    @foterio
    Мне тоже нужны были исторические данные по ценам и прайслисты.
    Я сделал сущность Price и таблицу к ней prices, со следующими полями
    currency как ENUM("EURO","USD","CNY","RUR")
    value как int, стоит заметить что мы храним деньги в копейках, центах и прочее
    created_at чтобы в будущем фильтровать их по дате

    Теперь везде, где мне нужна цена, я указываю price_id и все.

    Все расчеты внутри компании мы проводим в Долларах США.
    Там, где нужно выйти за пределы компании, можно запросить для каждой цены курс, так как дата этой цены известна в created_at.
    Ответ написан
  • Как проверить через JS загрузилось ли изображение?

    @foterio
    Только через onLoad, по другому никак. У меня все работает прекрасно.
    Ответ написан
    Комментировать
  • Как лучше делать пагинацию на React?

    @foterio
    Привыкайте запрашивать данные на клиент только, те, которые необходимы. Смысл от 200 товаров, если клиент увидит только 10. Ну или 30. У приложения будет лишний трафик + плата за использование Firebase.
    Запрашивайте первые 20 товаров, остальные подгружайте через useEffect. Все полученные товары кэшируйте на клиенте. Таким образом вы сократите нагрузку на backend и на сеть, так как пользователь может туда сюда по страницам ходить.
    Ответ написан
    Комментировать
  • Как возможно реализовать пагинацию поддокументов в mongodb через mongoose в express?

    @foterio
    MongoDB - документо-ориентированая база данных. Как вы храните объект так она вам его и возвращает.
    В вашем случае, я бы хранил только последние events на одну page в самом пользователе User, а когда нужно еще, то запрашивал уже остальные events из отдельной коллекции events с нужными skip и limit (заминусом тех events, которые вы уже показали из User.events).
    При добавлении нового Event в events, вы затем возьмете последние, например, 20 events с помощью skip и limit, и затем обновите поле User.events новыми последними 20-ю событиями.
    Это будет более-менее правильный подход в случае MongoDB.
    Если же у Вас много остальных связей и таких же полей, то стоит задуматься, а правильно ли выбрана база данных, и может подойдет реляционные типа Postgres, MySQL.
    Ответ написан
    Комментировать
  • Mongoose как обновлять обьект в массиве?

    @foterio
    1. Получаем документ из MongoDB
    const document = await ВашаСущность.findById(id)
    2. Берем массив чтобы удобнее с ним работать
    const bets = [...document.gameInfo.bets]
    3. Производим необходимые изменения
    // id ставки, которую нужно обновить
    const betId = 655037535
    // Получаем обновленный массив ставок
    const updatedBets = bets.map((bet) => {
      // Если betId совпадает с нашей ставкой, то изменяем объект
      if (bet.id == betId) return {
        ...bet,
        name: 'Новое значение поля Name',
      }
      // Остальные ставки остаются нетронутыми
      return bet
    })

    4. Сохраняем результат в MongoDB
    const update = {
      gameInfo: {
        ...document.gameInfo,
        bets,
      }
    }
    const updatedDocument = findOneAndUpdate({ _id: id }, update)
    Ответ написан
    Комментировать
  • Как сделать логику повторного элемента в корзине?

    @foterio
    Мои корзины в основном выглядят так
    const cart = [
      {
        productId: 123,
        quantity: 1,
      },
    ]


    При добавлении товара в корзину вы сначала ищете там productId, и если есть совпадение увеличиваете quantity на + 1
    Ответ написан
    Комментировать
  • Применение объекта req.query на сервере node js?

    @foterio
    1. Для SEO-оптимизации. Робот не нажимает на кнопки/фильтры и прочее. А просто ходит по страницам. И следовательно он не сможет нормально проиндексировать их. (не важно, если это внутренние корпоративные системы, личные кабинеты и прочее, там где необходима авторизация)
    2. Чтобы пользователи могли кидать ссылку друг другу и получать одинаковый результат. Также чтобы вы сами могли через баннеры или рекламу отправлять пользователя на нужные товары.
    3. SSR - для серверного рендеринг. Серверу при отработке запроса необходимо знать все данные, чтобы правильно отрендерить страницу и выдать готовый HTML за один заход. Поэтому все и передают эти параметры таким образом еще query.

    Вот здесь более подробно рассказывал как это работает
    https://qna.habr.com/q/1274714#answer_2331146
    Ответ написан
    Комментировать
  • Норма ли постоянное незначительное увеличение использования ОЗУ на сервере?

    @foterio
    Если NodeJS приложение не оптимально использует память и вы используете PM2, то решение есть.

    1. При запуске через консоль, установите максимальный лимит по RAM для NodeJS приложения
    pm2 start server.bundle.js --max-memory-restart 300M

    2. Либо в конфиге ecosystem.config.js для PM2
    module.exports = {
      apps: [{
        name: 'api',
        script: 'server.bundle.js',
        max_memory_restart: '300M'
      }]
    }


    Как только оно превысит 300 мегабайт, то PM2 просто сделает restart вашего приложения. И если у вас запущено несколько приложений в PM2 как cluster, то пользователи даже не заметят этого.
    Ответ написан
    Комментировать
  • Как спроектировать приложение? Или как лучше хранить данные?

    @foterio
    Обычно лайки храняться в отдельной таблице в базе данных аля likes
    и каждый лайк выглядит вот так
    {
      // Кто поставил лайк
      user_id: 123,
      // Какому изображению поставили лайк
      image_id: 456,
      // Когда поставили лайк, время в любом удобном для вас формате, (опционально)
      created_at: '2023-05-24 11:53'
    }

    И затем вы идете в likes и запрашиваете лайки для нужного вам изображения
    SELECT user_id, image_id, created_at FROM likes WHERE image_id = 456
    Ответ написан
    Комментировать
  • Общий доступ к данным хранимым в MySql?

    @foterio
    Если перейдете на Postgres (стоит его начать изучать), то можно использовать DBaaS (база данных как сервис) от cockroachlabs с их CockroachDB.
    Дают 10 гигов места для базы данных и 50 млн бесплатных запросов в месяц. Для старта вам хватит.
    Есть еще вариант Atlas но это MongoDB, они дают 512 мегабайт места для базы и тоже DBaaS. Но учитывайте, что MongoDB - это не реляционная база данных, не для всех случаев она подойдет.
    Ответ написан
    Комментировать
  • Какое решение применить для массового деплоя?

    @foterio
    Смотрите в сторону Github Actions.
    Можно настроить так, что как только происходит push в ветку main/master вашего репозитория, запускается action, в котором вы прописываете, что нужно делать и все. Один раз настроили и деплоить можно хоть вечность на n-машин.
    Ответ написан
    Комментировать
  • Фильтры товаров интернет-магазина, как грамотно реализовать обмен данными с сервером?

    @foterio
    Если это не GraphQL api, у которого любой запрос это POST, то общепринято для получения информации использовать GET запрос. Так же это сделано для того, чтобы вы могли поделиться этой ссылкой с другим человеком и еще чтобы правильно работало SEO.

    Выглядеть это должно примерно вот так.
    1. Для начала разберемся с pagination, тут есть два пути:
    А. Передавать два параметра, limit - кол-во записей, offset - отступ
    Первая страница /producst?limit=20&offset=0
    Вторая страница /producst?limit=20&offset=20

    B. Передавать только page, и уже на backend'е высчитывать limit и offset для обращения в БД
    Первая страница /producst
    Вторая страница /producst?page=2
    // Тут мы для первой страницы можем забить и не передавать никакие значения,
    // так как на backend'е предусматриваем page = 1 по дефолту.

    2. Значения фильтров так же передаем параметрами
    /producst?page=2&categoryIds=15,7,23
    3. И затем на backend'е уже парсим наши фильтры, незабывая предусмотреть дефолтные значения для фильтров. Есть разные подходы, первое что пришло в голову, это следующее решение
    let filter = {
      // тут можно предусмотреть некоторые значения фильтра по дефолту
      isAvailableOnStock: true,
    }
    // И затем парсим каждое значение
    if (query.categoryIds) {
      // В зависимости от базы данных, а так же драйвера и ORM,
      // которые мы используем, будет отличаться
      // делайте это в соответсвии с документацией
      filter.category_id = In(query.categoryIds.split(','))
    }
    // Делаем запрос в нашу базу
    // Для примера используется TypeORM
    const products = await getRepository(Products).find({
      // Используем наш объект filter
      where: {
        ...filter,
      },
      // Сортируем результат по названию
      order: {
        title: 'ASC',
      }
    })

    P. S. Еще помните, что существует сортировка, по цене, по имени, и прочее, которую так же необходимо передавать через параметр и затем сортировать результат из базы данных через "ORDER BY"
    Ответ написан
    Комментировать
  • Какой выбрать стэк для реализации заполнения постов в соцсетях?

    @foterio
    Если хотите работать с базой данных, то без backend'а особо уже не обойтись.
    Однако, существуют некоторые решения (DBaaS), например, Google Firestore/Firebase или у MongoDB тоже было какое-то похожее решение, где можно сделать сразу из коробки получить REST/GRAPHQL api на базу данных в их Atlas. Тут вопрос только в скорости выпуска продукта/денег.

    Для начала сделайте простое NodeJS приложение для обработки post запроса из вашей формы, работы с api vk и добавлением информации в бд.
    Если пишете с нуля, то express я бы не советовал, он давно устарел уже. Берите Fastify.
    Базу данных так же можно брать любую, смотрите в сторону Postgres/MongoDB, в вашем случае подойдет вообще все что угодно.
    Пример приложения можно найти на github по запросу fastify-mongodb или fastify-postgres
    Ответ написан
  • Что выбрать для бэкенда с нуля?

    @foterio
    Преимущество NodeJS - это ее асинхронность, и тут это нам сыграет на пользу. Плюс математические вычисления мы вынесем в отдельные worker'ы. Подробнее, как организовать worker pool тут https://github.com/josdejong/workerpool
    При правильно спроектированной архитектуре и настроенном NGINX, NodeJS способна переварить тысячи запросов и чувствовать себя отлично.
    У меня, к примеру в одном из проектов я уперся быстрее в производительность MongoDB на запись 165-220 RPS (на той конфигурации монги, которая была у заказчика), чем в невозможность обработать запрос клиента у NodeJS.
    Я бы начал с тестового backend'а на Fastify, так как мы все равно пишем с нуля и нам важна производительность. Будем честны для Go тут еще маловато нагрузки))))
    Затем пострелял бы в него из пушки, скажем 1000 RPS 10 секунд подряд и посмотрел результаты.
    Далее будет понятно, справляется ли один инстанс с этой задачей или нет, и тогда можно в случае чего масштабировать его и лить трафик на несколько NodeJS приложений через load balancer.
    Ответ написан
    Комментировать
  • Не получается настроить API-сервер. Как исправить? Как получить get-запрос?

    @foterio
    Используйте десктопное приложение Postman или Insomnia, чтобы иметь доступ к localhost
    Ответ написан
    Комментировать
  • Какой правильный деплой react + nodejs + nginx?

    @foterio
    Проверьте ваше React приложение.
    У него должно быть два состояния:
    development - когда вы разрабатываете его локально у себя на компе и backend тоже запущен у вас локально
    production - когда оно задеплоено у вас на сервере

    Затем в вашем коде, вы должны предусмотреть примерно следующее:

    // Тут проверяем в каком состоянии мы находимся
    const isDev = process.env.NODE_ENV === ‘development’
    //  Здесь мы меняем путь к нашему api
    const API_URL = isDev ? 'http://localhost:4000' : 'http://ваше-доменное-имя.com/api'
    // И затем уже подставляете ваш API_URL куда вам нужно
    app.post(`${API_URL}/users`, (req, res) => {
       console.log("fetch users")
    })


    Где localhost:4000 - это путь к вашему бэкенду у вас на компе, когда вы разрабатываете приложение
    http://ваше-доменное-имя.com/api - это путь к вашему backend'у, который запущен у вас на сервере

    P. S. Пример сделан для понимая базовых принципов, некоторые моменты специально упрощены. Как делать это красиво и более развернуто, можно поискать в инструкциях по запросу "development production variables react"
    Ответ написан
    Комментировать
  • Как в node.js express настроить параллельную работу?

    @foterio
    На тех вводных данных, которые Вы предоставили, я предлагаю следующее решение: использовать пакет node-cron

    Создаем отдельное приложение NodeJS, которое будет заниматься нашей задачей.

    const cron = require('node-cron');
    
    cron.schedule('* * * * *', () => {
      // Тут размещаете любые функции, которые хотите выполнять
      console.log('running a task');
    });


    Там где вот эти звездочки "* * * * *" - это и есть расписание, примеры из документации:
    "* * * * *" - работает каждую минуту (текущий пример кода выполняется каждую минуту"
    "0 0 * * *" - работает ежедневно в полночь
    "* 10,14 * * *" - работает ежедневно в 10:00 и 14:00

    Более подробно в документации тут https://github.com/node-cron/node-cron

    Само NodeJS приложение можно запускать разными способами, например, через PM2
    Ответ написан
    Комментировать