【问题标题】:How to merge these two objects in Angular JS?如何在 Angular JS 中合并这两个对象?
【发布时间】:2016-05-24 16:39:45
【问题描述】:

我需要帮助在 AngularJS 中合并两个对象 :)

我正在使用 trakt.tv API (http://docs.trakt.apiary.io/) 来提取历史数据。 这会返回用户观看过的电影和剧集列表(请参阅:http://docs.trakt.apiary.io/#reference/sync/get-history

如您所见,它不保存用户对特定电影或剧集的评分。 但是有一种方法可以获得所有用户对电影和电视节目等的评分。 (见http://docs.trakt.apiary.io/#reference/sync/get-ratings

所以我想做的是将用户的电影/剧集评级与历史列表中的电影/剧集进行匹配,但我就是不知道应该怎么做。

“历史”对象示例:

[
  {
    "id": 2008588422,
    "watched_at": "2016-05-17T10:36:12.000Z",
    "action": "watch",
    "type": "movie",
    "movie": {
      "title": "Batman v Superman: Dawn of Justice",
      "year": 2016,
      "ids": {
        "trakt": 129583,
        "slug": "batman-v-superman-dawn-of-justice-2016",
        "imdb": "tt2975590",
        "tmdb": 209112
      }
    }
  },
  {
    "id": 1995814508,
    "watched_at": "2016-05-09T22:39:47.000Z",
    "action": "checkin",
    "type": "movie",
    "movie": {
      "title": "Dirty Grandpa",
      "year": 2016,
      "ids": {
        "trakt": 188691,
        "slug": "dirty-grandpa-2016",
        "imdb": "tt1860213",
        "tmdb": 291870
      }
    }
  },
  {
    "id": 2005359787,
    "watched_at": "2016-05-09T01:00:00.000Z",
    "action": "watch",
    "type": "episode",
    "episode": {
      "season": 6,
      "number": 3,
      "title": "Oathbreaker",
      "ids": {
        "trakt": 1989021,
        "tvdb": 5579003,
        "imdb": "tt4131606",
        "tmdb": 1186952,
        "tvrage": 1065908650
      }
    },
    "show": {
      "title": "Game of Thrones",
      "year": 2011,
      "ids": {
        "trakt": 1390,
        "slug": "game-of-thrones",
        "tvdb": 121361,
        "imdb": "tt0944947",
        "tmdb": 1399,
        "tvrage": 24493
      }
    }
  }
]

“评分”对象示例:

[
  {
    "rated_at": "2016-05-17T10:36:28.000Z",
    "rating": 7,
    "type": "movie",
    "movie": {
      "title": "Batman v Superman: Dawn of Justice",
      "year": 2016,
      "ids": {
        "trakt": 129583,
        "slug": "batman-v-superman-dawn-of-justice-2016",
        "imdb": "tt2975590",
        "tmdb": 209112
      }
    }
  },
  {
    "rated_at": "2016-04-05T15:55:36.000Z",
    "rating": 8,
    "type": "movie",
    "movie": {
      "title": "You Don't Mess With the Zohan",
      "year": 2008,
      "ids": {
        "trakt": 5835,
        "slug": "you-don-t-mess-with-the-zohan-2008",
        "imdb": "tt0960144",
        "tmdb": 10661
      }
    }
  },
  {
    "rated_at": "2016-05-24T16:19:54.000Z",
    "rating": 8,
    "type": "episode",
    "episode": {
      "season": 6,
      "number": 3,
      "title": "Oathbreaker",
      "ids": {
        "trakt": 1989021,
        "tvdb": 5579003,
        "imdb": "tt4131606",
        "tmdb": 1186952,
        "tvrage": 1065908650
      }
    },
    "show": {
      "title": "Game of Thrones",
      "year": 2011,
      "ids": {
        "trakt": 1390,
        "slug": "game-of-thrones",
        "tvdb": 121361,
        "imdb": "tt0944947",
        "tmdb": 1399,
        "tvrage": 24493
      }
    }
  }
]

想要的结果:

[
  {
    "id": 2008588422,
    "rated_at": "2016-05-17T10:36:28.000Z",
    "rating": 7,
    "watched_at": "2016-05-17T10:36:12.000Z",
    "action": "watch",
    "type": "movie",
    "movie": {
      "title": "Batman v Superman: Dawn of Justice",
      "year": 2016,
      "ids": {
        "trakt": 129583,
        "slug": "batman-v-superman-dawn-of-justice-2016",
        "imdb": "tt2975590",
        "tmdb": 209112
      }
    }
  },
  {
    "id": 1995814508,
    "watched_at": "2016-05-09T22:39:47.000Z",
    "action": "checkin",
    "type": "movie",
    "movie": {
      "title": "Dirty Grandpa",
      "year": 2016,
      "ids": {
        "trakt": 188691,
        "slug": "dirty-grandpa-2016",
        "imdb": "tt1860213",
        "tmdb": 291870
      }
    }
  },
  {
    "id": 2005359787,
    "rated_at": "2016-05-24T16:19:54.000Z",
    "rating": 8,
    "watched_at": "2016-05-09T01:00:00.000Z",
    "action": "watch",
    "type": "episode",
    "episode": {
      "season": 6,
      "number": 3,
      "title": "Oathbreaker",
      "ids": {
        "trakt": 1989021,
        "tvdb": 5579003,
        "imdb": "tt4131606",
        "tmdb": 1186952,
        "tvrage": 1065908650
      }
    },
    "show": {
      "title": "Game of Thrones",
      "year": 2011,
      "ids": {
        "trakt": 1390,
        "slug": "game-of-thrones",
        "tvdb": 121361,
        "imdb": "tt0944947",
        "tmdb": 1399,
        "tvrage": 24493
      }
    }
  }
]

基本上评分数据应该添加到历史对象内的相应电影和剧集中。

angular.merge 或 .extend 没有给出想要的结果,这些似乎是非常基本的查看文档 (https://docs.angularjs.org/api/ng/function/angular.merge)

欢迎大家帮忙! :)

谢谢

【问题讨论】:

  • angular.merge 给你什么? angular.extend 能胜任吗?
  • 嗨@bmartin angular.merge 返回:pastebin.com/jkaDnfGS 和 angular.extend 给出:pastebin.com/K3pZ9RJd 两者都不是想要的结果:(
  • angular.merge 对我来说看起来正确吗?
  • 不是这样,评级只能添加到 History 对象中存在的电影和剧集。正如您在合并结果 (pastebin.com/jkaDnfGS) 中看到的那样,“脏爷爷”的电影对象变成了“你别惹Zohan”(评级数据只是简单地覆盖了历史对象)。
  • 另请注意,这只是一个示例,真实数据将是一个列表,可能是数百部电影和剧集的评级,以随机顺序排列。历史数据也是如此,在我的示例“蝙蝠侠大战超人:正义黎明”中始终是第一部电影,但情况可能并非如此。我需要某种可以识别特定电影(在历史对象中)的合并,并且只有当它具有该特定电影的评分数据时,才将该评分数据正确添加到电影对象中。

标签: javascript arrays angularjs object array-merge


【解决方案1】:

在操作员评论 ES6 不是一个选项后,我创建了一个 ES5 等效项,使用 find 辅助方法来模仿 ES6 的查找。

var merged = history.map(function (h) {
  var x = find(ratings, function (r) {
    return comparator(h, r);
  });

  return x ? angular.merge(h, x) : h;
});

/*
    Utility fn to get array.find style behaviour
*/
function find(arr, fn) {
  if (!Array.isArray(arr))
    return undefined;

  for(var i = 0; i < arr.length; i++){
    if (fn(arr[i]))
        return arr[i];
  }
}

fiddle


在我的评论中我说你可以使用 ES5 的 array.some 但我撒了谎。 some 将返回 true 如果单个匹配符合您的条件(适用于过滤器)但是我们想要实际的对象。

幸运的是 ES6 用find 再次拯救了我们; (你可以在 ES5 中使用过滤器,但这会给我们一个数组)

所以这样的事情应该很容易。

let merged = history.map(h => {
        let x =  ratings.find(r => comparator(r, h));
        return x ? angular.merge(h, x) : h;
    });

function comparator(review, history) {
    return review[review.type].ids.trakt === history[history.type].ids.trakt;
}

与往常一样,这是 ES6,所以 IE 最好不要出现。你可以通过 babel 之类的东西运行你的 ES6 来转换成 ES5,或者使用各种for loops 来完成上述所有操作。

Fiddle

【讨论】:

  • 嗨@ste2425,感谢您的详细回答!这几乎完成了我想要完成的工作,在最终结果中,对象应该具有历史数据,并在可用时将评级数据添加到项目中。正如您所指出的,您的结果还包括一部仅被评级的电影。但不应该出现在结果中,因为它不在用户历史记录中。 kangax.github.io/compat-table/es6 也表明移动设备 (android) 不支持 ES6。我正在构建一个 Ionic (ionicframework.com) 移动应用程序,所以这是一个问题。
  • 啊,所以你想翻转,所以历史是主人,如果它可用,它就有评级信息。这很容易。我强烈建议尝试实现符合 ES6 的代码并使用诸如 babel 之类的工具转换为 ES5。然后一旦浏览器赶上简单的转换。生病编辑答案。
  • 是的,没错!好的,期待您的更新答案:)
  • @webslash 已更新,希望对您有所帮助
  • 绝对精彩,按要求工作。非常感谢@ste2425!
猜你喜欢
  • 2015-08-18
  • 2023-04-08
  • 1970-01-01
  • 2019-10-08
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
相关资源
最近更新 更多