По сути, я настраиваю веб-сервер через Node.js и Express (я в этом новичок) для получения данных путем чтения файла JSON. Например, это мой файл data.json:
[{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
Я пытаюсь получить все цвета, реализовав этот код для отображения на localhost:
router.get('/colors', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
res.json(data); //this displays all of the contents of data.json
})
});
router.get('/colors:name', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
for (var i = 0; i < data.length; i++) {
res.json(data[i][1]); //trying to display the values of color
}
})
});
Как мне это сделать?
а внутри цикла должно понравиться что-то вроде этого data[i].color
Если, конечно, вы не хотите перебирать ключи, не зная их, тогда вы захотите использовать for(var key in data[i]) { var value = data[i][key]; }.
Все так просто. Просто используйте const newColors = data.map((item)=>item.color);
Небольшой момент, вы можете require() json файлы, а не читать и анализировать явно.

Что вы хотите сделать:
res.json(data[i]['color']);
Спасибо. Он работает, но отображает только первый элемент массива JSON. Я хотел бы перебрать его, чтобы отобразить все имена.
Я думаю, вы не можете получить доступ к JSON без ключа. Вы можете использовать цикл Foreach для (var name: object) {} проверки foreach, это может вам помочь
Это неправда, поскольку я видел, как это было сделано несколько раз. Однако моя проблема в том, что предоставленный мне файл JSON представляет собой массив без ключа.
Используйте цикл foreach 2 раза. Foreach будет работать как с массивом, так и с json для (var x: array) {for (var y: JSON) {x [y] // дает отдельный элемент u}}
в экспресс вы можете сделать таким образом
router.get('/colors/:name', (req, res) => {
const key = req.params.name
const content = fs.readFileSync(__dirname + '/data.json', 'utf8')
const data = JSON.parse(content)
const values = data.reduce((values, value) => {
values.push(value[key])
return values
}, [])
// values => ['black', 'red']
res.send(values)
});
а затем curl http://localhost/colors/color,
вы можете получить ['черный', 'красный']
Большое спасибо! Это помогло мне с моей проблемой. Можете ли вы объяснить, почему вы использовали readFileSync против readFile? А что делает сокращение? Я новичок, поэтому любые ресурсы мне очень помогут.
reduce для этого не нужен. readFileSync блокирует все, что было выполнено. Вы не хотите использовать это в производстве. Автор мог использовать это здесь для простоты. См. Мой комментарий по использованию .map()
@NidhinDavid хахаха, да, карта очень хорошая. но, пожалуйста, проголосуйте за меня, нам просто нужно 2 балла до 50, спасибо.
Если вы действительно не хотите использовать ключи в json, вы можете использовать функцию Object.values.
...
data = JSON.parse(data)
var values = []
for (var i = 0; i < data.length; i++) {
values.push(Object.values(data[i])[0]) // 0 - color, 1 - category, 2 - type
}
res.json(values) // ["black","red"]
...
То, что вы пытаетесь сделать, на самом деле довольно просто, если разбить его на более мелкие проблемы. Вот один из способов разобраться в этом:
var data = [];
try {
data = JSON.parse(fs.readFileSync('/path/to/json'));
} catch (e) {
// Handle JSON parse error or file not exists error etc
data = [{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
}
router.get('/colors', function (req, res, next) {
var colors = data.map(function (item) {
return item.color
}); // This will look look like: ["black","red"]
res.json(colors); // Send your array as a JSON array to the client calling this API
})
Некоторые улучшения в этом методе:
Array.prototype.mapДокументы для извлечения массива цветов из объекта.Примечание:
Вы можете структурировать массив цветов по своему усмотрению и отправить его в виде JSON в этой структуре.
Примеры:
var colors = data.map(function(item){return {color:item.color};}); // [{"color":"black"},{"color":"red"}]
var colors = {colors: data.map(function(item){return item.color;})} // { "colors" : ["black" ,"red"] }
Некоторые ошибки в вашем коде:
res.json в цикле for, что неверно, поскольку ответ должен быть отправлен только один раз. В идеале вы должны построить JS-объект в нужной вам структуре, перебирая ваши данные и отправляя завершенный объект один раз с помощью res.json (который, как я предполагаю, внутренне JSON.stringify передает объект и отправляет его в качестве ответа после установки правильных заголовков)Никогда не используйте fs.readFileSync в производстве. Любая функция синхронизации будет блокировать цикл событий до тех пор, пока выполнение не будет завершено, следовательно, задерживая все послесловия (при необходимости используйте с осторожностью). Несколько дней назад я сам испытал наихудший опыт и усвоил это на собственном горьком опыте.
В экспрессе вы можете определить маршрут с помощью param или query и использовать его для map содержимого внутри функции обратного вызова fs.readFile.
/**
* get color by name
*
* @param {String} name name of the color
* @return {Array} array of the color data matching param
*/
router.get('/colors/:name', (req, res) => {
const color = req.params.name
const filename = __dirname + '/data.json';
fs.readFile('/etc/passwd', 'utf8', (err, data) => {
if (err){
return res.send([]); // handle any error returned by readFile function here
}
try{
data = JSON.parse(data); // parse the JSON string to array
let filtered = []; // initialise empty array
if (data.length > 0){ // we got an ARRAY of objects, right? make your check here for the array or else any map, filter, reduce, forEach function will break the app
filtered = data.filter((obj) => {
return obj.color === color; // return the object if the condition is true
});
}
return res.send(filtered); // send the response
}
catch(e){
return res.send([]); // handle any error returned from JSON.parse function here
}
});
});
Подводя итог, используйте асинхронную функцию fs.readFile, чтобы цикл событий не был забит. Внутри обратного вызова анализируйте содержимое, а затем return ответ. return действительно важен, иначе вы можете получить Ошибка: не удается установить заголовки после их отправки
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ Этот код выше не тестировался, но должен работать. Это просто демонстрация идеи.
Привет. Отличный ответ. Тем не менее, я не согласен с некоторыми вашими замечаниями: 1) Неверно обобщать, говоря, что использование синхронизируемых версий всегда плохо. Это действительно зависит от того, как вы их используете, и они существуют по какой-то причине :) 2) возврат вызова res не является обязательным и не обязательно исключает ошибку, о которой вы упомянули. Это вызвано тем, что res отправляется несколько раз
Я полностью согласен с вами, @ChiragRavindra. Я, возможно, был ошеломлен, сказав, что не использую функции синхронизации. Я должен был сказать «используйте с осторожностью». И что касается возврата res, это просто мера предосторожности, когда пользователь может случайно вызвать res в следующем коде, который может быть выполнен. Так что возвращение не повредит, если это поможет избежать таких сценариев отправки множественных ответов, не так ли?
Ага. Возврат поможет предотвратить последующие вызовы (особенно если ваше промежуточное программное обеспечение использует условное выражение, которое использует отправку ответа, и есть код, который также отправляет другой ответ после этого). Я чувствовал, что важно подчеркнуть, что вызов returning the value of the res.send не обязательно препятствовал этому ошибка. (Один случай, когда это может произойти, если next вызывается перед res.send, который, в свою очередь, вызывает другое промежуточное программное обеспечение, которое также вызывает res.send). Опять же, я не хочу придираться .. Просто подумал, что стоит выделить эти моменты :)
Это было действительно мило с твоей стороны. Различные мнения действительно важны, поскольку они в первую очередь являются результатом разного опыта. Надеюсь, когда-нибудь наш аргумент поможет кому-то, даже мне. Очень признателен :)
Похоже, вам нужен старый добрый шлейф
for.... или, может быть, даже.forEach().