如何按子对象对对象数组进行分组?

时间:2017-11-18 07:01:56

标签: javascript arrays typescript grouping

我正在使用TypeScript作为Web应用程序的后端,我发现交集类型对于进行高效的SQL查询非常有用。基本上,如果我有以下表格:

User

userId: number
userEmail: string

Post

postId: number
userId: number (FK)
postBody: string

我最终会得到一个如下所示的交叉类型(User& Post):

{
  userId: number;
  userEmail: string;
  postId: number;
  postBody: string;
}

这意味着我可以使用此类型来表示从连接的选择查询中返回的行。

问题是我必须拆开Web服务器中的数据。我必须编写迭代代码来为每个查询分组它们,这可能会重复。这是我想要获得的那种转变:

在:

[
  {
    userId: 1,
    userEmail: 'user1@email.com',
    postId: 1,
    postBody: 'User 1\'s first post',
  },
  {
    userId: 1,
    userEmail: 'user1@email.com',
    postId: 2,
    postBody: 'User 1\'s second post',
  },
  {
    userId: 2,
    userEmail: 'user2@email.com',
    postId: 3,
    postBody: 'User 2\'s first post',
  },
]

输出:

[
  {
    userId: 1,
    userEmail: 'user1@email.com',
    posts: [
      {
        postId: 1,
        postBody: 'User 1\'s first post',
      },
      {
        postId: 2,
        postBody: 'User 1\'s second post',
      }
    ],
  },
  {
    userId: 2,
    userEmail: 'User 2\'s email',
    posts: [
      {
        postId: 3,
        postBody: 'User 2\'s first post',
      }
    ]
  }
]

我正在尝试提供一个我可以用来动态执行此操作的函数,可能传递集合,父键名称数组以及子集合的名称。我最终得到了一个带有以下签名的失败函数:function group(coll: Array<any>, parentKeys: Array<string>, childCollName: string): Array<any>;

我想知道是否有人可以帮我实现这个目标。

到目前为止,我已经尝试过使用Lodash了。但是,它的groupBy函数似乎无法判断子对象是否相等,在这个例子中它仍然给出了一个包含三个对象的数组。

3 个答案:

答案 0 :(得分:0)

如何尝试下面的内容,进入循环并创建对象

var arry = [
    {
        userId: 1,
        userEmail: 'user1@email.com',
        postId: 1,
        postBody: 'User 1\'s first post',
    },
    {
        userId: 1,
        userEmail: 'user1@email.com',
        postId: 2,
        postBody: 'User 1\'s second post',
    },
    {
        userId: 2,
        userEmail: 'user2@email.com',
        postId: 3,
        postBody: 'User 2\'s first post',
    },
];

function createPost(obj) {
    post = {};
    post.postId = obj.postId;
    post.postBody = obj.postBody;
    return post;
}
function convert(array) {
    var map = {};
    for (var i = 0; i < array.length; i++) {
        var currentObject = array[i];


        if (!map[currentObject.userId]) {
            obj = {}
            obj.userId = currentObject.userId;
            obj.userEmail = currentObject.userEmail;
            obj.posts = [];

            map[obj.userId] = obj;

        }
        obj.posts.push(createPost(currentObject));
    }
    var keys = Object.keys(map);
    return keys.map(function (v) { return map[v]; });
}
var r = convert(arry)
console.log(r);

答案 1 :(得分:0)

您可以使用Array.prototype.reduce()来实现目标。

&#13;
&#13;
var source =
    [
    {
        userId: 1,
        userEmail: 'user1@email.com',
        postId: 1,
        postBody: 'User 1\'s first post',
    },
    {
        userId: 1,
        userEmail: 'user1@email.com',
        postId: 2,
        postBody: 'User 1\'s second post',
    },
    {
        userId: 2,
        userEmail: 'user2@email.com',
        postId: 3,
        postBody: 'User 2\'s first post',
    },


]


var grouped = source.reduce(function(v,k){
    if (!v[k.userId]) {
        v[k.userId]={};
    }
    var group = v[k.userId];
    group.userId=k.userId;
    group.userEmail=k.userEmail;
    if(!group.posts){
        group.posts=[];
    }
    group.posts.push({postId: k.postId,
        postBody:k.postBody})
    return v;
},{})

var dataArray = [];
for(var o in grouped) {
    if (grouped.hasOwnProperty(o)) {
        dataArray.push(grouped[o]);
    }
}

console.log(JSON.stringify(dataArray,null, 2));
&#13;
&#13;
&#13;

答案 2 :(得分:0)

这是另一种减少,一些和解构的方法

DEMO

const grouped = [
  {
    userId: 1,
    userEmail: 'user1@email.com',
    postId: 1,
    postBody: 'User 1\'s first post',
  },
  {
    userId: 1,
    userEmail: 'user1@email.com',
    postId: 2,
    postBody: 'User 1\'s second post',
  },
  {
    userId: 2,
    userEmail: 'user2@email.com',
    postId: 3,
    postBody: 'User 2\'s first post',
  }
];

const sorted = grouped.reduce((acc, nxt) => {
    const { userId, userEmail, ...rest } = nxt;
    let index;
    let user;

    const accHasUser = acc.some((obj, i) => {
        if (obj && obj.userId === userId) {
            index = i;
            return true;
        }
        return false;
    });

    if (!accHasUser) {
        user = { userId, userEmail, posts: [rest] };
        acc.push(user);
    } else {
        acc[index].posts.push(rest);
    }

    return acc;
}, []);

console.log(JSON.stringify(sorted));