问题
var myObj =
data: {
{
chairId: "CHAIRCHROME009",
relatedOrders: [
{
someProp: 45423234,
data : {
firstOrder: {},
relatedOrders: [
{
someProp: 5757587,
data : {
firstOrder: {},
relatedOrders: [ ],
notifications: [
{
notificationId: "CHAIR-0909FF",
latestNotification: {
latestNotificationAction: "New",
priority: "High",
}
}
],
relations: [ ]
}
}
],
relations: [ ]
}
}
],
relations: [ ]
}
}
How can i endlessly loop through an object containing arrays and objects, essentially searching for a notifications
property.
In the example above, notifications is 2 levels deep in to myObj
, however it could be 1 level or 100 levels. notifications
will always be found under relatedOrders
I then need to determine the value of notifications.latestNotification.latestNotificationAction
If no notifications are found, null
or false
should be returned.
I have tried:
function isThereRelatedOrders(myObj) {
for(var k in myObj) {
var v = myObj[k];
if (k === "relatedOrders") {
isThereData(v[0]);
}
}
}
function isThereData(relatedOrder) {
for(var y in relatedOrder) {
var t = relatedOrder[y];
if (y === "data") {
isThereNotification(t);
}
}
}
function isThereNotification(t) {
for(var x in t) {
var j = t[x];
if (x === "notifications") {
console.lig('notifications found');
if(j[0].latestNotification.latestNotificationAction === "New") {
console.log('is new alert');
// Add a property to my original myObj root level of alert: new
}
else {
console.log('is old alert');
// Add a property to my original myObj root level of alert: old
}
}
else if(x === "relatedOrders") {
alert('SUB relatedOrders found');
isThereRelatedOrders(j[0]);
}
else {
alert('no notifications found');
}
}
}
isThereRelatedOrders(myObj);
With the above, once my code has got to calling isThereRelatedOrders() for the second time, it never hits the if statement.. I guess its becuase is now need to look for .data??
With the above executed, i would want something like this to be retunred:
var myObj = {
chairId: "CHAIRCHROME009",
alert: "New"
////////
回答1:
This proposal uses an iterative and recursive approach to get the wanted property notifications
and their content. If one found, the content is pushed into the result
array. If nothing is found, then the array remains empty.
function iter(o) {
if (Array.isArray(o)) {
o.forEach(iter);
return;
}
if (typeof o === 'object') {
Object.keys(o).forEach(function (k) {
if (k === 'chairId') {
chairId = o[k];
}
if (k === 'notifications') {
o[k].forEach(function (a) {
if ('latestNotificationAction' in a.latestNotification) {
result.push({
chairId: chairId,
alert: a.latestNotification.latestNotificationAction
});
}
});
}
iter(o[k]);
});
}
}
var myObj = { data: { chairId: "CHAIRCHROME009", relatedOrders: [{ someProp: 45423234, data: { firstOrder: {}, relatedOrders: [{ someProp: 5757587, data: { firstOrder: {}, relatedOrders: [], notifications: [{ notificationId: "CHAIR-0909FF", latestNotification: { latestNotificationAction: "New", priority: "High", } }], relations: [] } }], relations: [] } }], relations: [] } },
chairId,
result = [];
iter(myObj);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Edit:
A solution which respects the toggle between data
and relatedOrders
properties.
function iter(o, flip) {
if (Array.isArray(o)) {
o.forEach(function (a) {
iter(a, flip);
});
return;
}
if (typeof o === 'object') {
if ('chairId' in o) {
chairId = o.chairId;
}
if (
flip === 'relatedOrders' &&
'notifications' in o &&
0 in o.notifications &&
'latestNotification' in o.notifications[0] &&
'latestNotificationAction' in o.notifications[0].latestNotification
) {
result.push({
chairId: chairId,
alert: o.notifications[0].latestNotification.latestNotificationAction
});
return;
}
flip in o && iter(o[flip], flipFlop[flip]);
}
}
var myObj = { data: { chairId: "CHAIRCHROME009", relatedOrders: [{ someProp: 45423234, data: { firstOrder: {}, relatedOrders: [{ someProp: 5757587, data: { firstOrder: {}, relatedOrders: [], notifications: [{ notificationId: "CHAIR-0909FF", latestNotification: { latestNotificationAction: "New", priority: "High", } }], relations: [] } }], relations: [] } }], relations: [] } },
chairId,
result = [],
flipFlop = { relatedOrders: 'data', data: 'relatedOrders' };
iter(myObj, 'data');
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
回答2:
Here's my attempt, using your data, but cleaned up to be valid... Click on the "Run code snippet" button to run it.
var myObj = {
data: {
chairId: "CHAIRCHROME009",
relatedOrders: [{
someProp: 45423234,
data: {
firstOrder: {},
relatedOrders: [{
someProp: 5757587,
data: {
firstOrder: {},
relatedOrders: [],
notifications: [{
notificationId: "CHAIR-0909FF",
latestNotification: {
latestNotificationAction: "New",
priority: "High",
}
}],
relations: []
}
}],
relations: []
}
}],
relations: []
}
};
function findAllNotifications(obj, chairId) {
var result = [];
Object.keys(obj).forEach(function(prop) {
if (prop === 'chairId') {
chairId = obj.chairId;
}
if (prop === 'notifications') {
obj.notifications.forEach(function(notif) {
result.push({
chairId: chairId,
alert: notif.latestNotification.latestNotificationAction
});
});
}
switch (typeof obj[prop]) {
case 'object':
result = result.concat(findAllNotifications(obj[prop], chairId));
break;
case 'array':
obj[prop].forEach(function(sub) {
result = result.concat(findAllNotifications(sub, chairId));
});
break;
}
});
return result;
}
var result = findAllNotifications(myObj);
console.log("Result:", result);
// Doing this so you can see the result on the web page...
document.body.appendChild(document.createTextNode(JSON.stringify(result)));
// To "reassign" to the original object:
// myObj= findAllNotifications(myObj);
回答3:
JSONPath is a perfect match for such tasks. It is very flexible and makes a lot of fun. 😀
You can download an actual fork here: https://github.com/s3u/JSONPath
1. simple task, simple solution:
If there is only one chair in your data, you could easily get the chairId and let JSONPath do the rest:
var result = {
chairId: myObj.data.chairId,
alert: JSONPath({json: myObj, wrap: false, path: '$..latestNotificationAction'}) || false
};
var resultString = JSON.stringify(result, 0, 4);
document.write('<pre>' + resultString + '</pre>');
<script src="https://raw.githack.com/s3u/JSONPath/master/lib/jsonpath.js"></script>
<script>
var myObj = {
data: {
chairId: "CHAIRCHROME009",
relatedOrders: [{
someProp: 45423234,
data: {
firstOrder: {},
relatedOrders: [{
someProp: 5757587,
data: {
firstOrder: {},
relatedOrders: [],
notifications: [{
notificationId: "CHAIR-0909FF",
latestNotification: {
latestNotificationAction: "New",
priority: "High",
}
}],
relations: []
}
}],
relations: []
}
}],
relations: []
}
};
</script>
2. complex task, simple solution:
If your data is more complex, you can use a callback function, which will be called every time a chair with a latestNotification
is found:
function find(obj, foundCallBack) {
JSONPath({
json: obj, resultType: 'parent', wrap: false,
path: '$..chairId',
callback: function(chair) {
JSONPath({
json: chair, resultType: 'parent', wrap: false,
path: '$..latestNotification',
callback: function(notification) {foundCallBack({
chairId: chair.chairId,
alert: notification.latestNotification.latestNotificationAction,
priority: notification.latestNotification.priority
})}});
}});
}
find(myObj, function(result){
var resultString = JSON.stringify(result, 0, 4);
alert(resultString);
document.write('<pre>' + resultString + '</pre>');
});
<script src="https://raw.githack.com/s3u/JSONPath/master/lib/jsonpath.js"></script>
<script>
var myObj = {
data: {
employees: [1, 2, 3, 4],
chairs: [
{
chairId: "CHAIRCHROME009",
relatedOrders: [{
someProp: 45423234,
data: {
firstOrder: {},
relatedOrders: [{
someProp: 5757587,
data: {
firstOrder: {},
relatedOrders: [],
notifications: [{
notificationId: "CHAIR-0909FF",
latestNotification: {
latestNotificationAction: "New1",
priority: "High",
}
},
{
notificationId: "CHAIR-0909FF",
latestNotification: {
latestNotificationAction: "New2",
priority: "Medium",
}
}],
relations: []
}
}],
relations: []
}
}],
relations: []
},
{
chairId: "CHAIRCHROME0077",
relatedOrders: [{
someProp: 45423234,
data: {
firstOrder: {},
relatedOrders: [{
someProp: 5757587,
data: {
firstOrder: {},
relatedOrders: [],
notifications: [{
notificationId: "CHAIR-090922FF",
latestNotification: {
latestNotificationAction: "New3",
priority: "Low",
}
}],
relations: []
}
}],
relations: []
}
}],
relations: []
}
]
}
};
</script>
来源:https://stackoverflow.com/questions/36087992/loop-through-object-searching-for-property-and-modify-original-object-on-success