Firebase: snapshot.val не является функцией или ее возвращаемое значение не является итеративным

#javascript #node.js #reactjs #firebase #express

#javascript #node.js #reactjs #firebase #выразить

Вопрос:

Итак, я создаю небольшое приложение, используя Express, Firebase и ReactJS. Я застопорился из-за проблемы с Firebase snapshot.val

Эта часть кода в express обслуживает мои поездки по идентификатору и для получения всех. Для всех поездок работает нормально, но когда я пытаюсь перейти к единственной поездке, она возвращает мне эту ошибку

если я разрушу его как массив:

Предупреждение о необработанном promiserejectionwarning: TypeError: snapshot.val не является функцией или его возвращаемое значение не является итеративным

Если я разрушу его как объект:

Ошибка типа: не удается уничтожить свойство trip , имеющее значение ‘undefined’ или ‘null’.

и я полностью сбит с толку и не могу найти решение.

Вот часть кода, выраженная:

 const firebase = require('firebase');

const reference = () => firebase.database().ref('/trips')

exports.getSingle = async (id) => {
  //const snapshot = await reference()
  //  .orderByChild('id')
  //  .equalTo(id)
  //  .limitToFirst(1)
  //  .once('value');

  // const [trip] = snapshot.val();
  //  return trip
const snapshot = await reference()
    .orderByChild('id')
    .equalTo(parseInt(id, 10))
    .limitToFirst(1)
    .once('value');
  let trip = [];
  snapshot.forEach(function (tripSnapshot) {
    tripStorage = tripSnapshot.val();
    console.log(tripStorage);
    trip.push(tripStorage);
  });
  console.log(trip);
  return trip;
};

exports.getAll = async () => {
  const snapshot = await reference().once('value');

  return snapshot.val();
};
  

Я извлекаю trips во внешнем интерфейсе с:

  componentDidMount() {
    fetch("/api/trips/get/"   this.state.id)
      .then(res => res.json())
      .then(trip =>
        this.setState({
          trip
        }, () => console.log("Trips fetched...", trip))
      );
  }
  

Контроллер для отключений:

 const express = require('express');

const route = express.Router();
const tripUtil = require('../utils/tripUtil');

route.get('/getAll', async (req, res) => {
  const trips = await tripUtil.getAll();

  res.json(trips);
});

route.get('/get/:id', async (req, res) => {
  const { id } = req.params;
  const trip = await tripUtil.getSingle(id);

  if (trip) {
    res.json(trip);
  } else {
    res.status = 400;
    res.json({
      error: 'trip not found'
    });
  }
});

module.exports = route;
  

И отображение свойств из объекта, подобного этому:

  {this.state.trip.itinerary.days.map((day, i) => {
     return (
       <div key={i} className="trip-single-item__day">
          <div className="trip-single-item__day-header">
              <div className="trip-single-item__day-title">
                 {day.title}
              </div>
              <div className="trip-single-item__day-subtitle">
                 {day.subtitle}
              </div>
              <div className="trip-single-item__day-date">
                 {day.date}
              </div>
          </div>
          <div className="trip-single-item__day-body">
             <div className="trip-single-item__day-descritpion">
               {day.description}
             </div>
          </div>
      </div>
      );
  })}
  

Вот изображение одного отключения Single trip в firebase

Есть предложения или указания? Спасибо

Комментарии:

1. почему вы помещаете trip константу в квадратные скобки? const [trip] = snapshot.val(); Вы пытаетесь получить доступ к свойству trip из snapshot.val() , например const { trip } = snapshot.val();

2. Если я размещаю его так, как вы предлагаете, то я получаю необработанное предупреждение promiserejectionwarning: TypeError: не удается уничтожить свойство trip ‘undefined’ или ‘null’. Но я подумал, что это правильный способ деконструировать объект firebase?

3. это был просто вопрос, а не предложение 🙂 Можете ли вы отредактировать свой пост и написать ошибку: it returns me this error and I am totally baffled

4. Готово, спасибо за совет. Зачем я это делаю? Когда я немного думаю об этом, если оно хранится как объект в firebase, то нет логики для доступа к нему через квадратные скобки, но теперь я еще больше запутался, почему отключение не определено.

5. Является ли id свойство вложенным свойством одного trip объекта? Если нет, вы можете получить к нему доступ следующим образом: reference().child(id) .once(‘значение’)`

Ответ №1:

Firebase обычно рекомендует не хранить данные в виде массивов в базе данных реального времени (хотя существуют некоторые исключения): https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html

Я предполагаю, что по какой-то причине значение вашего снимка отображается не как массив, а как объект с цифровыми клавишами. Одной из причин этого может быть то, что ключи в Firebase не являются строго последовательными, поскольку Firebase будет отображать ваши данные в виде массива, только если ключи данных начинаются с 0 и в них нет пробелов.

Можете ли вы попробовать этот код, чтобы посмотреть, работает ли он?

 exports.getSingle = async (id) => {
  const snapshot = await reference()
    .orderByChild('id')
    .equalTo(id)
    .limitToFirst(1)
    .once('value');

  const queryResult = snapshot.val()
  console.log(queryResult) // Make note of the object shape here. Make sure there are actually results.

  const trip = Object.values(queryResult)[0]
  return trip;
};
  

Комментарии:

1. Он просто возвращает QueryResult как null, поэтому кажется, что ссылка на databse не подходит. Я также отредактировал код контроллера, который обслуживает ID и все, может быть, я чего-то там не хватает?

2. Похоже. orderByChild, .equalTo и limitToFirst создают проблему, и я не совсем понимаю, почему.

3. :id Параметр, который вы получаете из Express и передаете в getSingle , скорее всего, является строкой, а id свойство trip в Firebase — это число. Это может привести к сбою вашего equalTo запроса, поскольку он не может найти элемент с id === «1». Попробуйте equalTo(parseInt(id, 10)) и посмотрите, решит ли это проблему.

4. Да, это решило проблему с идентификатором, который, очевидно, был строкой. Но довольно странная вещь происходит после того, как мне пришлось обновить код для отправки snapshot.val() в массив trip, и отправленные элементы отлично отображаются в JSON до его отправки, но при отправке вложенные элементы внутри отображаются как [object Объект].

5. Глубоко вложенные объекты JSON часто будут отображаться как [Object] или [object object] при входе в консоль с помощью console.log. Это нормально. Вы можете попробовать console.log(JSON.stringify(trips, null, 2)) сериализовать объект и распечатать его в виде строки.

Ответ №2:

Может быть необработанное предупреждение promiserejectionwarning.

Обработайте свой снимок с помощью then / catch

 exports.getSingle = async (id) => {
  await reference()
    .orderByChild('id')
    .equalTo(id)
    .limitToFirst(1)
    .once('value').then(snapshot => {

         const [trip] = snapshot.val();
         return trip

        //  console.log(post.id)  if required
    })
};

  

Комментарии:

1. Да, это выдает, UnhandledPromiseRejectionWarning Я отредактировал ошибку. Просматривал документацию firebase и попробовал некоторые варианты, подобные опубликованным вами, но по-прежнему выдает мне ту же ошибку.