用Angular JS基于id合并数组中的多个对象
Merging multiple objects in an array with Angular JS based on id
我已经搜索了一段时间,试图找到这个问题的答案,因为我想象有人遇到这种情况。请指出我在正确的方向,如果答案已经在那里。我有一个包含图书的对象数组。这些书存储在数据库中,可以有一个或多个作者。对于writers表中的每个writer,都有一个用于book_id(FK)、writer_name和review_id(FK)的列。因此,如果一本书上有多个作者,则每个作者都有一行包含除了名字以外的相同信息。下面是一个来自DB的JSON响应示例:
var data = [
{"id": 1, "writer" : "John Joseph Doe", "review_id" : 4},
{"id": 1, "writer" : "Daniel Smith", "review_id" : 4},
{"id": 1, "writer" : "Thomas Edward Jones", "review_id" : 4},
{"id": 2, "writer" : "Erin Davis", "review_id" : 5},
{"id": 2, "writer" : "Jill Steinberg", "review_id" : 5},
{"id": 2, "writer" : "Laurie Beth Jennings", "review_id" : 5},
{"id": 3, "writer" : "Emma Jean Williams", "review_id" : 3},
{"id": 3, "writer" : "Mary Joe Williams", "review_id" : 3},
{"id": 3, "writer" : "Helen Andrews", "review_id" : 3},
{"id": 3, "writer" : "Samantha Jones", "review_id" : 3}
];
我想过滤这个数组,这样我最终得到3个对象,每本书一个,没有重复值,每个作者连接为逗号分隔的字符串。像这样:
var data = [
{"id": 1, "writer" : "John Joseph Doe, Daniel Smith, Thomas Edward Jones", "review_id" : 4},
{"id": 2, "writer" : "Erin Davis, Jill Steinberg, Laurie Beth Jennings", "review_id" : 5},
{"id": 3, "writer" : "Emma Jean Williams, Mary Joe Williams, Helen Andrews, Samantha Jones", "review_id" : 3}
];
因此,我尝试创建一个函数,该函数使用for循环和'first'变量来根据它的id跟踪我所在的对象。我的逻辑是将每个写入器添加到具有唯一id的每个对象的第一个实例中,然后在添加写入器后删除具有相同id的所有后续对象。因此,每个图书id只剩下一个对象和一个用逗号分隔的作者连接字符串。结果很接近我想要的,但是我做得不对。我不确定是否从数组中删除对象是我的问题,或者我是否采取了完全错误的方法。这里有一个工作小提琴:http://jsfiddle.net/mlabita37/Lvc0u55v/8987/。表上方有一个文本区,我使用它作为"控制台"来显示最终数据数组,只需展开即可看到完整的结果。
下面是该代码的一些片段:
HTML:<div ng-controller="BookCtrl">
<table class="table table-striped">
<thead>
<tr>
<th>Book ID</th>
<th>Writer</th>
<th>Review ID</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="book in books">
<td>{{ book.id }}</td>
<td>{{ book.writer }}</td>
<td>{{ book.review_id }}</td>
<textarea>{{ books }}</textarea>
</tr>
</tbody>
控制器:
var data = [
{"id": 1, "writer" : "John Joseph Doe", "review_id" : 4},
{"id": 1, "writer" : "Daniel Smith", "review_id" : 4},
{"id": 1, "writer" : "Thomas Edward Jones", "review_id" : 4},
{"id": 2, "writer" : "Erin Davis", "review_id" : 5},
{"id": 2, "writer" : "Jill Steinberg", "review_id" : 5},
{"id": 2, "writer" : "Laurie Beth Jennings", "review_id" : 5},
{"id": 3, "writer" : "Emma Jean Williams", "review_id" : 3},
{"id": 3, "writer" : "Mary Joe Williams", "review_id" : 3},
{"id": 3, "writer" : "Helen Andrews", "review_id" : 3},
{"id": 3, "writer" : "Samantha Jones", "review_id" : 3}
];
combine = function(data){
var first = data[0];
for(var i = 1; i < data.length; i++){
if(data[i].id === first.id){
first.writer = first.writer + ", " + data[i].writer;
data.splice(i, 1);
}
if(data[i].id !== first.id){
first = data[i];
var j = i+1;
if(data[j].id === first.id){
first.writer = first.writer + ", " + data[j].writer;
data.splice(j, 1);
}
}
}
};
combine(data);
$scope.books = data;
我的另一个想法是使用过滤器,但我没有太多的经验,不知道这是否是一个更好的方法。我也不确定这是否可以/应该在我的MySQL查询中处理,或者在后端PHP中处理。我的印象是这个问题最好在前端处理。
var data = [
{"id": 1, "writer" : "John Joseph Doe", "review_id" : 4},
{"id": 1, "writer" : "Daniel Smith", "review_id" : 4},
{"id": 1, "writer" : "Thomas Edward Jones", "review_id" : 4},
{"id": 2, "writer" : "Erin Davis", "review_id" : 5},
{"id": 2, "writer" : "Jill Steinberg", "review_id" : 5},
{"id": 2, "writer" : "Laurie Beth Jennings", "review_id" : 5},
{"id": 3, "writer" : "Emma Jean Williams", "review_id" : 3},
{"id": 3, "writer" : "Mary Joe Williams", "review_id" : 3},
{"id": 3, "writer" : "Helen Andrews", "review_id" : 3},
{"id": 3, "writer" : "Samantha Jones", "review_id" : 3}
];
function existsAt(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] == value) {
return i;
}
}
return false;
}
var _data = [];
_data.push(data[0]);
for (var i = 1; i < data.length; i++) {
var alreadyExistsAt = existsAt(_data, 'id', data[i].id);
if (alreadyExistsAt !== false) {
_data[alreadyExistsAt].writer += ', ' + data[i].writer;
} else {
_data.push(data[i]);
}
}
document.body.innerHTML = JSON.stringify(_data);
我希望代码中的变量名能够很好地解释。
- 外部
forEach
回路依次从完整的评审列表中选择每个评审(即currReview
)。 - 内部的
forEach
循环遍历每个预先存在的连接的书评对象(即prevReviewsForThisBook
…一开始是空的)。这个内循环确定当前的评论是否针对已经至少有一个评论的书:- 如果是,则更新该预先存在的审阅对象的
writer
属性以包含新的编写器。 - 如果不是,那么整个当前评论对象将被推送到已有的书评对象数组中。
- 如果是,则更新该预先存在的审阅对象的
请注意,您的id
(可能是您的book_id
)始终与您的review_id
相同。这是你想要的吗?似乎其中一个是多余的/不必要的,或者其中一个是计算/确定不正确的。后者似乎是可能的。例如,John Joseph Doe所做的review的review_id
和Daniel Smith所做的review的review_id
都应该具有相同的值4吗?我认为这些是单独的评论,因此应该有不同的review_id
值,即使它们都有相同的id
/book_id
值(因为这两个人都评论了同一本书)。这个问题不是回答这个问题的核心,但您可能需要重新考虑。
var data = allReviews = [
{"id": 1, "writer" : "John Joseph Doe", "review_id" : 4},
{"id": 1, "writer" : "Daniel Smith", "review_id" : 4},
{"id": 1, "writer" : "Thomas Edward Jones", "review_id" : 4},
{"id": 2, "writer" : "Erin Davis", "review_id" : 5},
{"id": 2, "writer" : "Jill Steinberg", "review_id" : 5},
{"id": 2, "writer" : "Laurie Beth Jennings", "review_id" : 5},
{"id": 3, "writer" : "Emma Jean Williams", "review_id" : 3},
{"id": 3, "writer" : "Mary Joe Williams", "review_id" : 3},
{"id": 3, "writer" : "Helen Andrews", "review_id" : 3},
{"id": 3, "writer" : "Samantha Jones", "review_id" : 3}
];
var reviewsByBook = [];
allReviews.forEach(function(currReview) {
var currReviewIsForNewBook = true;
reviewsByBook.forEach(function(prevReviewsForThisBook) {
if (currReview.id === prevReviewsForThisBook.id) {
prevReviewsForThisBook.writer += ", " + currReview.writer;
currReviewIsForNewBook = false;
}
});
if (currReviewIsForNewBook) {
reviewsByBook.push(currReview);
}
});
console.log(reviewsByBook);
- Javascript(Angular)从一个对象数组到第二个数组查找值
- 在Javascript中转换对象数组
- 在JavaScript中通过索引从对象数组中获取值
- Backbone虹吸以获取对象数组
- 如何在DataTables 2.1中迭代对象数组
- Javascript-根据赋值顺序,按键合并对象数组
- 将事件附加到对象/数组
- jQuery$.inArray()总是返回-1和一个对象数组
- javascript处理一个对象数组以获得一个新的对象数组
- javascript在数组中获取对象数组中键的所有不同值
- 在对象数组中查找多个值的d3范围
- Undercore.js获取对象数组中键对象的值
- 在mongoose中使用正则表达式在对象数组中进行查询搜索
- 如何通过json对象数组为嵌套对象赋值
- 如何循环通过2个对象数组并通过匹配id进行合并
- 为对象数组创建列表项
- 如何使用javascript合并两个对象数组
- JSON到对象数组,并向每个对象添加项
- JavaScript:从对象数组中获取唯一值及其计数
- 按不同项目对对象数组进行排序