在JSON对象上使用jQuery的find()方法

74

brnwdrng的问题类似,我正在寻找一种方法来搜索类似JSON的对象。
假设我的对象结构如下:

TestObj = {
    "Categories": [{
        "Products": [{
            "id": "a01",
            "name": "Pine",
            "description": "Short description of pine."
        },
        {
            "id": "a02",
            "name": "Birch",
            "description": "Short description of birch."
        },
        {
            "id": "a03",
            "name": "Poplar",
            "description": "Short description of poplar."
        }],
        "id": "A",
        "title": "Cheap",
        "description": "Short description of category A."
    },
    {
        "Product": [{
            "id": "b01",
            "name": "Maple",
            "description": "Short description of maple."
        },
        {
            "id": "b02",
            "name": "Oak",
            "description": "Short description of oak."
        },
        {
            "id": "b03",
            "name": "Bamboo",
            "description": "Short description of bamboo."
        }],
        "id": "B",
        "title": "Moderate",
        "description": "Short description of category B."
    }]
};

我想获取id为"A"的对象。

我尝试了各种方法,比如:

$(TestObj.find(":id='A'"))

但是似乎什么都不起作用。

有没有人想到一种根据某些条件检索项目的方法,而不使用“each”?


2
  1. 你有一个普通的JavaScript对象,而不是类似JSON的对象。你只需要使用对象字面量表示法来定义它,而JSON只是它的子集(但JSON在完全不同的上下文中工作)。http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/
  2. jQuery在DOM上工作,而不是任意对象上。你正在使用错误的工具来完成工作。除了循环遍历产品数组之外,没有其他方法。
- Felix Kling
6个回答

121

jQuery在普通对象字面量上无法工作。您可以使用以下函数以类似的方式搜索所有'id'(或任何其他属性),而不考虑其在对象中的深度:

function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            objects.push(obj);
        }
    }
    return objects;
}

使用方式如下:

getObjects(TestObj, 'id', 'A'); // Returns an array of matching objects

2
这不是一个 JSON 对象。这也意味着你应该避免使用 for...in 循环来遍历数组。 - Felix Kling
1
@Felix,我想这取决于您希望数组的预期结果是什么。即使使用正常方式创建数组([]),您仍然可以向其中添加(非数字)属性,这些属性可能需要或不需要进行迭代。除此之外,检查 hasOwnProperty() 可以防止迭代原型中的属性。 - David Tang
1
@Box9:没错。看来我太专注于for...in和数组了,以至于我没有真正意识到你在使用hasOwnProperty()做什么......不过没关系,我收回之前的话;)并且点个赞作为补偿:o) - Felix Kling
@Box9 我刚才想象你是恩里克·伊格莱西亚斯唱着“我可以成为你的英雄宝贝!” - capdragon
@Box9:我正在尝试使用您的代码查找和更新。怎么做?https://dev59.com/rmMl5IYBdhLWcg3w9q3u - Okky
显示剩余5条评论

52

纯javascript方案更好,但使用jQuery的方法是使用jQuery grep和/或map方法。 可能不比使用$.each优秀。

jQuery.grep(TestObj, function(obj) {
    return obj.id === "A";
});
或者
jQuery.map(TestObj, function(obj) {
    if(obj.id === "A")
         return obj; // or return obj.name, whatever.
});
返回匹配的对象数组,或在映射情况下返回查找的值数组。也许您可以简单地使用它们来实现您想要的功能。但是在这个例子中,由于数据不是一个平坦的数组,并且我们接受任意结构、键和值,就像纯Javascript解决方案一样,所以您需要做一些递归处理。
function getObjects(obj, key, val) {
    var retv = [];

    if(jQuery.isPlainObject(obj))
    {
        if(obj[key] === val) // may want to add obj.hasOwnProperty(key) here.
            retv.push(obj);

        var objects = jQuery.grep(obj, function(elem) {
            return (jQuery.isArray(elem) || jQuery.isPlainObject(elem));
        });

        retv.concat(jQuery.map(objects, function(elem){
            return getObjects(elem, key, val);
        }));
    }

    return retv;
}

实质上与Box9的答案基本相同,但在适当时使用jQuery实用程序函数。


3
我使用了这个代码: jQuery.grep(TestObj, function(obj) { return obj.id === "A"; })[0].PropertyName; - Luis Robles
3
使用 $.grep() 的人需要记住它返回的是一个数组。这意味着如果你想查找单个项目,你需要使用 $.grep(/* 任何 */)[0] 来访问它。 - Jason
1
$.grep()刚刚为我省下了一场巨大的头痛。我的问题/解决方案与 OP 无关,但这让我只需要查询一次数据库,而不是n次。太棒了! - edwardrbaker
@davepncj 如果我比较字符串,那么对象中有一个字母是小写的,而在比较的字符串中是大写的。那么我们如何忽略这种大小写的差异呢? - Bhavin Thummar

5

这对我来说很有效,适用于 [{"id":"数据"},{"id":"数据"}]

function getObjects(obj, key, val) 
{
    var newObj = false; 
    $.each(obj, function()
    {
        var testObject = this; 
        $.each(testObject, function(k,v)
        {
            //alert(k);
            if(val == v && k == key)
            {
                newObj = testObject;
            }
        });
    });

    return newObj;
}

3
对于一维的JSON,您可以使用以下代码:
function exist (json, modulid) {
    var ret = 0;
    $(json).each(function(index, data){
        if(data.modulId == modulid)
            ret++;
    })
    return ret > 0;
}

2
您可以使用JSONPath
做类似这样的事情:
results = JSONPath(null, TestObj, "$..[?(@.id=='A')]")

请注意,JSONPath 返回一个结果数组。
(顺便说一句,我还没有测试过表达式"$..[?(@.id=='A')]"。也许需要在浏览器控制台的帮助下进行微调。)

-4

我想提及的另一个选项是,您可以将数据转换为XML,然后按照您想要的方式使用jQuery.find(":id='A'")

有一些jQuery插件可以实现此效果,例如json2xml

可能没有转换开销值得,但对于静态数据来说,这只是一次成本,因此可能会很有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接