npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

simple-object-query

v1.6.1

Published

Find object recursively by query

Downloads

2,408

Readme

simple-object-query

Build Status

npm install simple-object-query

bower install simple-object-query

Really simple lib to find a deep value in an object

I'll use this source object for all examples

var source = {
    data: [
        {
            item: {
                name: 'select',
                options: {
                    length: 4,
                    property: {
                        name: 'input'
                    }
                }
            }
        },
        {
            item: {
                name: 'group',
                options: {
                    length: 2,
                    property: {
                        name: 'input'
                    }
                },
                type: 'number'
            }
        }
    ]
};

get

This function will return value of deep field if it is own property. You can use * if you don't know exact index in array.

var get = require('simple-object-query').get;

get(source, 'data.*.item.name'); // 'select'
get(source, 'data.1.item.name'); // 'group'
get(source, 'data.*.item.type'); // 'number'

Basically you will use this method only when you need a * because without it you can get value just with regular code.

where

This is filter function for array. It will return all items which deep fields will be equal to query values. You can use regular expression to test deep field value.

var where = require('simple-object-query').where;

where(source.data, {
    'item.name': /(select|group)/,
    'item.type': 'number',
    'item.options': function (value) {
    	return typeof value === 'object';
    }
});
/*
 [
   {
        item: {
            name: 'group',
            type: 'number',
            options: {...},
        }
    }
 ]
*/

You can do even more complicated query with array of queries. Items of this array can be one of three types:

  1. Object - regular query
  2. Function - should be map function which will return new value instead of previous result
  3. String - shortcut for map function with get function with current query string (item) => get(item, string)
var src = {
    root: {
        node: [
            {a: {b: 1}},
            {a: {c: 2}},
            {a: {d: 3, g: [{e: 3},{f: 4}]}},
            {a: {d: 3, g: [{e: 5},{f: 5}]}},
            {a: {d: 4, g: [{e: 3},{f: 4}]}},
            {a: {d: 4, g: [{e: 5},{f: 5}]}}
        ]
    }
};

var q = require('simple-object-query'),
    _ = require('underscore');

q.where(src.root.node, [
    {
        'a.d': 3
    },
    'a.g',
    _.flatten, // or lite version (single level) analog q.flatten
    {
        'e': 5
    }
]);
/*
 [
  {a: {d: 3, g: [{e: 5},{f: 5}]}}
 ]
*/

find

This function will recursively find a deep object which has deep fields as in query object and their values are equal to values from query object. As values in query object you can use regular expressions.

var find = require('simple-object-query').find;

find(source, {
    'options.property.name': 'input'
});
/*
 [
  {name: 'select', options: {...}},
  {name: 'group', options: {...}}
 ]
*/

find(source, {
    'name': 'group',
    'options.property.name': 'input'
});
/*
 [
  {name: 'group', options: {...}}
 ]
*/

find(source, {
    'options.length': /\d+/
});
/*
 [
  {name: 'select', options: {...}},
  {name: 'group', options: {...}}
 ]
*/

search

Difference between find is that it takes parameters as object of type

{
    source: object,
    query: object, // same object as for "find"
    exclude: array, // array of names of properties which are links to other objects in source (circular links)
    recursion: true, // deep search or not
    callback: function (object) {} // optional callback for each found target
}

If you will not set callback then search will return array of objects of next type

{
    parent: object, // link to parent object
    field: 'string', // name of parent property of target object
    target: object, // searched object
    path: ['path', 'to', 'object'] // this path means that target is in source.path.to.object property
}

Warning: if your input object has circular links (like parent fields or like previousSibling in DOM) then you should set path to this fields in exclude array to prevent endless recursion.

var search = require('simple-object-query').search;

search({
    source: source,
    query: {
        'options.property.name': 'input'
    }
});
/*
 [
  {
    parent: {item: {...}},
    field: 'item',
    path: ['data', '0', 'item'],
    target: {name: 'select', options: {...}}
  },
  {
    parent: {item: {...}},
    field: 'item',
    path: ['data', '1', 'item'],
    target: {name: 'group', options: {...}}
  }
 ]
*/

source.data[0].item.list = source.data;

search({
    source: source,
    query: {
        'length': 2
    },
    exclude: [
        'list',
        // or more specifically
        'item.list'
    ]
});
/*
 [
  {
    parent: {name: 'group', options: {...}},
    field: 'options',
    path: ['data', '1', 'item', 'options'],
    target: {length: 2, property: {...}}
  }
 ]
*/

replace

This method will replace or remove (if callback will return undefined) target object.

var replace = require('simple-object-query').replace;

replace(source, {length: /\d+/}, function (target, parent, field, path) {
    return target.length > 3 ? 'test' : undefined;
});

console.log(source.data[0].item.options); // 'test'
console.log(source.data[1].item.hasOwnProperty('options')); // false

Off course if you don't want to remove target just return itself.

Instead of callback you can pass some value.

replace(source, {length: /\d+/}, 'test');

console.log(source.data[0].item.options); // 'test'
console.log(source.data[2].item.options); // 'test'

Or if you will not pass anything it will remove all targets

replace(source, {length: /\d+/});

console.log(source.data[0].item.hasOwnProperty('options')); // false
console.log(source.data[1].item.hasOwnProperty('options')); // false

If your target is in array, it will be removed correctly

replace(source, {name: 'select'});

console.log(source.data.length); // 1
console.log(source.data[0].item.name); // 'group'

If you need set exclude parameter then you should pass all parameters as object just like for search only with callback parameter

replace({
    source: source,
    query: {length: /\d+/},
    exclude: ['item.list'],
    callback: function (target, parent, field, path) {
        return target.length > 3 ? 'test' : undefined;
    }
});