Как получить доступ к содержимому файла JSON без ключа?

По сути, я настраиваю веб-сервер через 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
        }
    })
});

Как мне это сделать?

Похоже, вам нужен старый добрый шлейф for .... или, может быть, даже .forEach().

Derek Pollard 13.06.2018 05:09

а внутри цикла должно понравиться что-то вроде этого data[i].color

Derek Pollard 13.06.2018 05:10

Если, конечно, вы не хотите перебирать ключи, не зная их, тогда вы захотите использовать for(var key in data[i]) { var value = data[i][key]; }.

Derek Pollard 13.06.2018 05:11

Все так просто. Просто используйте const newColors = data.map((item)=>item.color);

Nidhin David 13.06.2018 05:51

Небольшой момент, вы можете require() json файлы, а не читать и анализировать явно.

Paul 13.06.2018 06:20
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
0
5
1 394
6

Ответы 6

Что вы хотите сделать:

res.json(data[i]['color']);

Спасибо. Он работает, но отображает только первый элемент массива JSON. Я хотел бы перебрать его, чтобы отобразить все имена.

feedmecookies 13.06.2018 05:38

Я думаю, вы не можете получить доступ к JSON без ключа. Вы можете использовать цикл Foreach для (var name: object) {} проверки foreach, это может вам помочь

Это неправда, поскольку я видел, как это было сделано несколько раз. Однако моя проблема в том, что предоставленный мне файл JSON представляет собой массив без ключа.

feedmecookies 13.06.2018 05:44

Используйте цикл foreach 2 раза. Foreach будет работать как с массивом, так и с json для (var x: array) {for (var y: JSON) {x [y] // дает отдельный элемент u}}

saketh 13.06.2018 05:51

в экспресс вы можете сделать таким образом

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? А что делает сокращение? Я новичок, поэтому любые ресурсы мне очень помогут.

feedmecookies 13.06.2018 05:42

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

Nidhin David 13.06.2018 06:26

@NidhinDavid хахаха, да, карта очень хорошая. но, пожалуйста, проголосуйте за меня, нам просто нужно 2 балла до 50, спасибо.

孙欣乐 13.06.2018 08:26

Если вы действительно не хотите использовать ключи в 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"]
...

То, что вы пытаетесь сделать, на самом деле довольно просто, если разбить его на более мелкие проблемы. Вот один из способов разобраться в этом:

  1. Загрузите данные JSON в память для использования вашим API.
  2. Определите маршрут API, который извлекает только цвета из ваших данных JSON и отправляет их клиенту в виде JSON.

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
})

Некоторые улучшения в этом методе:

  1. Файл считывается только один раз синхронно при запуске приложения, и данные кэшируются в памяти для использования в будущем.
  2. Использование 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"] }

Некоторые ошибки в вашем коде:

  1. Вы используете res.json в цикле for, что неверно, поскольку ответ должен быть отправлен только один раз. В идеале вы должны построить JS-объект в нужной вам структуре, перебирая ваши данные и отправляя завершенный объект один раз с помощью res.json (который, как я предполагаю, внутренне JSON.stringify передает объект и отправляет его в качестве ответа после установки правильных заголовков)
  2. Чтение файлов - дорогостоящая операция. Если вы можете позволить себе прочитать его один раз и кэшировать эти данные в памяти, это будет эффективно (при условии, что ваши данные не являются чрезмерно большими - в этом случае использование файлов для хранения информации может быть неэффективным для начала)

Никогда не используйте 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 отправляется несколько раз

Chirag Ravindra 13.06.2018 12:09

Я полностью согласен с вами, @ChiragRavindra. Я, возможно, был ошеломлен, сказав, что не использую функции синхронизации. Я должен был сказать «используйте с осторожностью». И что касается возврата res, это просто мера предосторожности, когда пользователь может случайно вызвать res в следующем коде, который может быть выполнен. Так что возвращение не повредит, если это поможет избежать таких сценариев отправки множественных ответов, не так ли?

maksbd19 13.06.2018 12:45

Ага. Возврат поможет предотвратить последующие вызовы (особенно если ваше промежуточное программное обеспечение использует условное выражение, которое использует отправку ответа, и есть код, который также отправляет другой ответ после этого). Я чувствовал, что важно подчеркнуть, что вызов returning the value of the res.send не обязательно препятствовал этому ошибка. (Один случай, когда это может произойти, если next вызывается перед res.send, который, в свою очередь, вызывает другое промежуточное программное обеспечение, которое также вызывает res.send). Опять же, я не хочу придираться .. Просто подумал, что стоит выделить эти моменты :)

Chirag Ravindra 14.06.2018 11:13

Это было действительно мило с твоей стороны. Различные мнения действительно важны, поскольку они в первую очередь являются результатом разного опыта. Надеюсь, когда-нибудь наш аргумент поможет кому-то, даже мне. Очень признателен :)

maksbd19 14.06.2018 12:27

Другие вопросы по теме