Итак, я создаю небольшое приложение, используя Express, Firebase и ReactJS. Я наткнулся на проблему с Firebase snapshot.val
Эта часть кода на экспрессе обслуживает мои поездки по идентификатору и получает все. Для всех поездок работает нормально, но когда я пытаюсь перейти к одиночной поездке, мне возвращается эта ошибка.
если я деструктурирую его как массив:
UnhandledPromiseRejectionWarning: TypeError: snapshot.val is not a function or its return value is not iterable
Если я деструктурирую его как объект:
TypeError: Cannot destructure property
tripof 'undefined' or '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.info(tripStorage);
trip.push(tripStorage);
});
console.info(trip);
return trip;
};
exports.getAll = async () => {
const snapshot = await reference().once('value');
return snapshot.val();
};
Я получаю поездки в интерфейсе с помощью:
componentDidMount() {
fetch("/api/trips/get/" + this.state.id)
.then(res => res.json())
.then(trip =>
this.setState({
trip
}, () => console.info("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>
);
})}
Вот изображение одной поездки Одиночная поездка в firebase
Любые предложения или направления? Спасибо
Если я размещу его так, как вы предлагаете, я получу UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property trip «undefined» или «null». Но я подумал, что это правильный способ деконструировать объект firebase?
это был просто вопрос, а не предложение :) Можешь отредактировать свой пост и написать ошибку: it returns me this error and I am totally baffled
Готово, спасибо за подсказку. Почему я это делаю? Когда я немного думаю об этом, если он хранится как объект в firebase, тогда нет логики для доступа к нему через квадратные скобки, но теперь я еще больше запутался, почему поездка не определена.
Является ли свойство id вложенным свойством одного объекта trip? Если нет, вы можете получить к нему доступ следующим образом: reference().child(id).once('value')`
Да, идентификатор является вложенным объектом одиночного trip.
Я пытался воспроизвести вашу проблему, но безуспешно. У меня есть несколько вопросов: вы звоните firebase.initializeApp перед вашей просьбой? И другая идея - проверить правила вашей базы огня. Есть ли у вас какие-либо особые правила или проверки в отношении одного объекта поездки?
Да, я звоню firebase.initializeApp. Правила тоже в порядке. Если вы посмотрите, есть код для получения всех поездок, я предполагаю, что он не будет работать, если firebase.initializeApp и правила не сохранены должным образом. Я также прикреплю структуру базы данных в редактировании.
К сожалению, у меня больше нет идей. Вы уверены, что getSingle получает правильный id в качестве параметра? Вы можете попробовать упростить запрос... начните с await reference().once('value'), затем попробуйте с await reference().child(0).once('value') и проверьте результаты. Также уберите эти квадратные скобки, просто const trip = snapshot.val(); return trip;
Поместите свой код, чтобы сначала попытаться поймать. Посмотрите на ошибку. Я думаю, вы пропустили добавление правил в firebase, поэтому нет ошибки разрешения.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Может быть UnhandledPromiseRejectionWarning.
Обработайте свой снимок с помощью 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.info(post.id) if required
})
};
Да выдает, UnhandledPromiseRejectionWarning Я отредактировал ошибку. Просматривал документацию firebase и пробовал некоторые варианты, как вы опубликовали, но все равно выдает ту же ошибку.
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.info(queryResult) // Make note of the object shape here. Make sure there are actually results.
const trip = Object.values(queryResult)[0]
return trip;
};
Он просто возвращает queryResult как null, поэтому кажется, что ссылка на базу данных не годится. Я также отредактировал код контроллера, который обслуживает идентификатор и все, может быть, я что-то упускаю?
Похоже, что .orderByChild, .equalTo и limitToFirst создают проблему, и я не могу понять, почему.
Параметр :id, который вы получаете от Express и передаете в getSingle, скорее всего, является строкой, а свойство id поездки в Firebase — числом. Это может привести к сбою вашего запроса equalTo, поскольку он не может найти элемент с идентификатором === "1". Попробуйте equalTo(parseInt(id, 10)) и посмотрите, решит ли это проблему.
Да, это решило часть с идентификатором, который, очевидно, был строкой. Но довольно странная вещь происходит после того, как мне пришлось обновить код для помещения snapshot.val() в массив отключения, и отправленные элементы отображаются в JSON нормально до того, как они будут отправлены, но при перемещении вложенные элементы внутри отображаются как [object Object].
Глубоко вложенные объекты JSON часто отображаются как [Object] или [object Object] при входе в консоль с помощью console.info. Это нормально. Вы можете попробовать console.info(JSON.stringify(trips, null, 2)) сериализовать объект и распечатать его в виде строки.
Это беспокоило меня, и я все-таки это понял, но мне удалось сделать это, 2 вещи отсутствовали equalTo(parseInt(id, 10)) и этот фрагмент кода для рендеринга поездок pastebin.com/V6EgP3SB
почему вы заключаете константу
tripв квадратные скобки?const [trip] = snapshot.val();Вы пытаетесь получить доступ к свойствуtripизsnapshot.val(), напримерconst { trip } = snapshot.val();