Searching for JSON data in JavaScript

Is there a more efficient approach for searching data in JSON other than using loops? This is specifically for editing and deleting purposes.

for(var k in objJsonResp) {
  if (objJsonResp[k].txtId == id) {
    if (action == 'delete') {
      objJsonResp.splice(k,1);
    } else {
      objJsonResp[k] = newVal;
    }
    break;
  }
}

The data is structured as a list of maps. For example:

[
  {id:value, pId:value, cId:value,...},
  {id:value, pId:value, cId:value,...},
  ...
]

Answer №1

(Stop looking for "JSON", you're actually browsing through an array -- the JSON string has already been converted into an object graph, specifically an array in this case.)

Here are a few options:

Utilize an Object Instead of Array

If you have control over creating this, does it necessarily need to be an array? If not, there's a simpler way.

Consider the original data:

{
    "one":   {"pId": "foo1", "cId": "bar1"},
    "two":   {"pId": "foo2", "cId": "bar2"},
    "three": {"pId": "foo3", "cId": "bar3"}
}

This makes finding the relevant entry by ID simple:

id = "one"; // Or any other
var entry = objJsonResp[id];

...as well as updating it:

objJsonResp[id] = /* New value */;

...and removing it:

delete objJsonResp[id];

This leverages the fact that in JavaScript, you can access an object using a property name as a string, which can be a literal or from a variable like id.

Adding an ID-to-Index Map

(Outdated idea, provided before the previous option. Included for historical reasons.)

If you must use an array, then searching through it may be unavoidable unless you add a map to it during generation, assuming you have control over it. For example, with initial data like:

{
    "index": {
        "one": 0, "two": 1, "three": 2
    },
    "data": [
        {"id": "one",   "pId": "foo1", "cId": "bar1"},
        {"id": "two",   "pId": "foo2", "cId": "bar2"},
        {"id": "three", "pId": "foo3", "cId": "bar3"}
    ]
}

Retrieving an entry based on the id becomes straightforward:

var index = objJsonResp.index[id];
var obj = objJsonResp.data[index];

This approach capitalizes on the ability to access objects using property names.

Although maintaining the map when modifying the array could pose challenges.

If you lack control over object generation or managing the id-to-index map is cumbersome, resorting to brute force search might be necessary.

Brute Force Search (updated)

Not directly related (but you did ask for alternatives :-)), your loop code for arrays is incorrect. Refer to this article for details. Avoid using for..in to iterate through array indexes; instead, stick with traditional loops:

var k;
for (k = 0; k < someArray.length; ++k) { /* ... */ }

or

var k;
for (k = someArray.length - 1; k >= 0; --k) { /* ... */ }

Select your preferred method (the latter isn't universally faster in all cases, contrary to intuition). When dealing with a sparse array, take care if considering for..in; more information in the linked article.

Though using for..in on an array can appear to function correctly due to each index having its own property, any additional properties set on the array object will disrupt this behavior (valid since arrays are objects with special handling for the length property).

Answer №2

When faced with a complex model involving nested objects, I encountered an interesting dilemma. Imagine having a polaroid of yourself placed in a trunk of a car, which is then stored inside a crate within the hold of a large ship filled with numerous other crates. To find a solution, I had to navigate through the various layers by searching the hold, inspecting the crates, checking the trunk, and finally locating an existing picture of myself.

Although many online solutions recommended using .filter() on arrays, it wasn't applicable in this case. Most suggested simply checking if model["yourpicture"] existed, but that would only scratch the surface (or in this case, search the hold of the ship). I needed a method to delve deeper into the nested structure.

This led me to create a recursive solution, after confirming with T.J. Crowder that recursion was indeed necessary. I decided to share my implementation in case others encounter a similar intricate scenario.

function ContainsKeyValue( obj, key, value ){
    if( obj[key] === value ) return true;
    for( all in obj )
    {
        if( obj[all] != null && obj[all][key] === value ){
            return true;
        }
        if( typeof obj[all] == "object" && obj[all]!= null ){
            var found = ContainsKeyValue( obj[all], key, value );
            if( found == true ) return true;
        }
    }
    return false;
}

Using this recursive function, I can start from a specified object and recursively explore any nested objects. Here's how I utilize it:

var liveData = [];
for( var items in viewmodel.Crates )
{
    if( ContainsKeyValue( viewmodel.Crates[items], "PictureId", 6 ) === true )
    {
        liveData.push( viewmodel.Crates[items] );
    }
}

This snippet generates an array of the Crates that contain my picture within them.

Answer №3

If you're looking to simplify searching through JSON data without the need to convert it into objects, consider utilizing DefiantJS, a JavaScript library designed for this purpose. Instead of restructuring the JSON data, you can search through its structure using an XPath expression like the example below:

var data = [
   {
      "id": "one",
      "pId": "foo1",
      "cId": "bar1"
   },
   {
      "id": "two",
      "pId": "foo2",
      "cId": "bar2"
   },
   {
      "id": "three",
      "pId": "foo3",
      "cId": "bar3"
   }
],
res = JSON.search( data, '//*[id="one"]' );

console.log( res[0].cId );
// 'bar1'

DefiantJS enhances the functionality of the global object JSON by introducing a new method called "search," which returns an array of matching results (or an empty array if no matches are found). You can experiment with this feature by entering your JSON data and testing various XPath queries on the following website:

It's worth noting that XPath is a standardized query language commonly used for this type of operation.

Answer №4

When looking through your array of JSON data, keep in mind that if the data is already sorted, you have several search options available to you. But if your dataset is small, sticking with an O(n) operation like you currently have is likely sufficient. Implementing anything more complex might be unnecessary and excessive for your needs.

Answer №5

Although this post may be old, it could still provide valuable assistance to someone else in need. The issue of backward compatibility is mentioned here, but given the phase-out of Internet Explorer, it has become somewhat irrelevant.

If you are looking for a straightforward solution to achieve your desired outcome, consider the following code snippet:

function findInJson(objJsonResp, key, value, aType){        
     if(aType=="edit"){
        return objJsonResp.find(x => x[key] == value);
     }else{//delete
         var a =objJsonResp.find(x => x[key] == value);
         objJsonResp.splice(objJsonResp.indexOf(a),1);
     }
}

By using this function, you can easily locate and modify the desired item by specifying 'edit' as the type. Alternatively, omitting any input or providing a different value will trigger the deletion functionality. Feel free to adjust the conditionals according to your preference.

Answer №6

Generic Solution

Our team relies heavily on object-scan for various data processing tasks. This tool offers some great features, particularly when it comes to traversing in a delete-safe sequence. Here’s an example of how you could apply methods like find, delete, and replace to address your specific query.

// const objectScan = require('object-scan');

const utility = (() => {
  const scanner = objectScan(['[*]'], {
    abort: true,
    rtn: 'bool',
    filterFn: ({
      value, parent, property, context
    }) => {
      if (value.id === context.id) {
        context.fn({ value, parent, property });
        return true;
      }
      return false;
    }
  });
  return {
    add: (data, id, obj) => scanner(data, { id, fn: ({ parent, property }) => parent.splice(property + 1, 0, obj) }),
    del: (data, id) => scanner(data, { id, fn: ({ parent, property }) => parent.splice(property, 1) }),
    mod: (data, id, prop, v = undefined) => scanner(data, {
      id,
      fn: ({ value }) => {
        if (value !== undefined) {
          value[prop] = v;
        } else {
          delete value[prop];
        }
      }
    })
  };
})();

// -------------------------------

const data = [ { id: 'one', pId: 'foo1', cId: 'bar1' }, { id: 'three', pId: 'foo3', cId: 'bar3' } ];
const toAdd = { id: 'two', pId: 'foo2', cId: 'bar2' };

const execute = (fn) => {
  console.log('---------------');
  console.log(fn.toString());
  console.log(fn());
  console.log(data);
};

execute(() => utility.add(data, 'one', toAdd));
execute(() => utility.mod(data, 'one', 'pId', 'zzz'));
execute(() => utility.mod(data, 'one', 'other', 'test'));
execute(() => utility.mod(data, 'one', 'gone', 'delete me'));
execute(() => utility.mod(data, 'one', 'gone'));
execute(() => utility.del(data, 'three'));

// => ---------------
// => () => utility.add(data, 'one', toAdd)
// => true
// => [ { id: 'one', pId: 'foo1', cId: 'bar1' }, { id: 'two', pId: 'foo2', cId: 'bar2' }, { id: 'three', pId: 'foo3', cId: 'bar3' } ]
// => ---------------
// => () => utility.mod(data, 'one', 'pId', 'zzz')
// => true
// => [ { id: 'one', pId: 'zzz', cId: 'bar1' }, { id: 'two', pId: 'foo2', cId: 'bar2' }, { id: 'three', pId: 'foo3', cId: 'bar3' } ]
// => ---------------
// => () => utility.mod(data, 'one', 'other', 'test')
// => true
// => [ { id: 'one', pId: 'zzz', cId: 'bar1', other: 'test' }, { id: 'two', pId: 'foo2', cId: 'bar2' }, { id: 'three', pId: 'foo3', cId: 'bar3' } ]
// => ---------------
// => () => utility.mod(data, 'one', 'gone', 'delete me')
// => true
// => [ { id: 'one', pId: 'zzz', cId: 'bar1', other: 'test', gone: 'delete me' }, { id: 'two', pId: 'foo2', cId: 'bar2' }, { id: 'three', pId: 'foo3', cId: 'bar3' } ]
// => ---------------
// => () => utility.mod(data, 'one', 'gone')
// => true
// => [ { id: 'one', pId: 'zzz', cId: 'bar1', other: 'test', gone: undefined }, { id: 'two', pId: 'foo2', cId: 'bar2' }, { id: 'three', pId: 'foo3', cId: 'bar3' } ]
// => ---------------
// => () => utility.del(data, 'three')
// => true
// => [ { id: 'one', pId: 'zzz', cId: 'bar1', other: 'test', gone: undefined }, { id: 'two', pId: 'foo2', cId: 'bar2' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a8c7cac2cdcbdc85dbcbc9c6e8999b869f8699">[email protected]</a>"></script>

Please note: The author behind object-scan is part of our team.

Answer №7

If you find yourself needing this functionality in multiple sections of your application, it might be beneficial to consider utilizing a client-side JSON database. Crafting custom search functions can become messy and harder to maintain compared to using an alternative solution.

Take a look at ForerunnerDB, a robust client-side JSON database system that offers a straightforward query language designed to assist you in achieving your desired results:

// Initialize a new instance of ForerunnerDB and retrieve a database
var fdb = new ForerunnerDB(),
    db = fdb.db('myTestDatabase'),
    coll;

// Create a new collection (similar to a MySQL table) and modify the default
// primary key from "_id" to "id"
coll = db.collection('myCollection', {primaryKey: 'id'});

// Add our data records to the collection
coll.insert([
    {"name":"my Name","id":12,"type":"car owner"},
    {"name":"my Name2","id":13,"type":"car owner2"},
    {"name":"my Name4","id":14,"type":"car owner3"},
    {"name":"my Name4","id":15,"type":"car owner5"}
]);

// Search the collection for the specified string "my nam" as a case insensitive
// regular expression - this search will match all records because every
// name field contains the text "my Nam"
var searchResultArray = coll.find({
    name: /my nam/i
});

console.log(searchResultArray);

/* Outputs
[
    {"name":"my Name","id":12,"type":"car owner"},
    {"name":"my Name2","id":13,"type":"car owner2"},
    {"name":"my Name4","id":14,"type":"car owner3"},
    {"name":"my Name4","id":15,"type":"car owner5"}
]
*/

Please note: The developer of ForerunnerDB is responsible for this content.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Solr Time Conversion

Having a dilemma with Solr dates: Here is the format of my time frames: TimeFrame_From:2018-02-28T05:00:02.0Z TimeFrame_To: 2018-02-28T06:00:02.0Z I've created code using the SimpleDateFormat function. public void validateParameters(String Ti ...

notifying users via email in a React application with data saved in Firebase database

In order to notify users of upcoming deadlines, I need to send an email when they are approaching. The deadline is saved in Firebase as a specific date and time (mm/dd/yyyy mm: hh), associated with the user's account email address ([email protect ...

Setting up React Router in a nested directory with a flexible route structure

As a newcomer to react router, I am seeking guidance on setting it up in a specific scenario. Imagine we have a PHP application running on 'http://www.example.com'. Within this setup, there is a react application located at 'http://www.examp ...

What is the process for exporting an NPM module for use without specifying the package name?

I am looking for a way to export an NPM module so that it can be used without specifying the package name. Traditionally, modules are exported like this: function hello(){ console.log("hello"); } module.exports.hello = hello; And then imported and ...

Can you explain how this promise functions within the context of the mutation observer, even without an argument?

Recently, I came across a mutation observer in some TypeScript code that has left me puzzled. This particular implementation of a promise within the mutation observer seems unconventional to me: const observer = new MutationObserver((mutations: MutationR ...

After reaching the conclusion, the code restarts

Any ideas on how to reset this code every 10-20 seconds? I'm struggling to find a solution! I'm new to coding, so any assistance would be greatly appreciated. Here's the code: var items = document.getElementsByClassName('btn-primary n ...

Generate a fresh array by appending a JSON element and inserting a new attribute into the same JSON object that was appended

I have a JSON array and I am looking to create a new array where I can push all childNodes along with their respective funding source names. var data = vardata={ "costdata": [ { fundingSource: 'A', childNode: [ ...

Creating a unique Vue.js modal window for every individual product

Currently, I am in the process of creating a small online store using Vue.js. Within this store, I have a variety of products each with unique names and prices. In order to provide more information about each product, I have included a "Details" button. M ...

Transform information within logstash using hierarchical JSON structures

I am currently working on a sample log entry (JSON) and below is the content: { "Order": { "content": { "seqnum": "107", "type": "DAIRY", "sect ...

Retrieve combination values through an AJAX request using ExtJS

My UI is developed using ExtJS, and I have a specific set of tasks that need to be executed when the page loads: Initiate an ajax call to the server to fetch a HashMap. Create a combobox within the main Panel on the page. var combo = Ext.create(' ...

When two $scopes are updated simultaneously, it leads to the duplication of data

Here is the snippet of code I am working with: $scope.addToOrder = function(index) { var tempItem = $scope.item; if (tempItem[index].validate == true){ if (_.isEmpty($scope.item2) == true) { $scope.item2.push ...

Is there a way to create a universal script that works for all modal windows?

I have a dozen images on the page, each opening a modal when clicked. Currently, I've created a separate script for each modal. How can I consolidate these scripts into one for all modals? <!-- 1 Modal--> <div class="gallery_product col-lg-3 ...

Designing functions with HTML

I have been working on creating a Coffeescript function that incorporates common HTML for an object that is frequently used on my page. To make the content dynamic, I am passing a variable to the function which will be replaced each time it is called. Unfo ...

The concept of recursion in AngularJS directives

I developed a unique custom directive. angular.module('menu',[]) .directive('MenuDirective',function(){ return{ restrict:'E', replace:'true', scope:{ m ...

Exploring the life cycle of React.js components, how state behaves within them, and the asynchronous nature

There seems to be an issue with the expected data result and the actual data result. Even though the fetchData() and fetchnumberOfCommits() methods are being called from the componentWillMount(), the array is empty at first. However, the render method is b ...

Guide on How to Retrieve the Following YouTube Video using a PHP Array

I have a PHP/HTML script that currently loads a random YouTube video from an array every time the page is refreshed. However, I am looking to add functionality for next and previous buttons to allow users to cycle through the videos in the array. The goal ...

Phase 2 "Loading" visual backdrop

I'm attempting to include a loading animation GIF in my Cycle 2 plugin. Is there a way to ensure that the GIF loads before the images? Right now, I have set my loading.gif as a background image. The issue is that the loading.gif isn't displaying ...

Sublime Text 3 for React.js: Unveiling the Syntax Files

Currently, my code editor of choice is Sublime Text 3. I recently wrote a simple "hello world" example in React, but the syntax highlighting appears to be off. I attempted to resolve this issue by installing the Babel plugin, however, the coloring still re ...

With Crypto-JS, a fresh hash is always generated

I'm looking to integrate crypto-js into my Angular 8 application. Here is a snippet of my code: import {Injectable} from '@angular/core'; import * as CryptoJS from 'crypto-js'; @Injectable() export class HprotoService { public ...

Having trouble with the function not running properly in HTML?

I'm having trouble implementing a copy button on my HTML page. Despite no errors showing in the chrome console, the text just won't copy. Below is a snippet of my HTML code: <!doctype html> <div class="ipDiv tk-saffran"> <div c ...