【问题标题】:Convert a relation SQL table into JSON using R使用 R 将关系 SQL 表转换为 JSON
【发布时间】:2015-09-01 22:43:06
【问题描述】:

我正在尝试使用 R 将 SQL 表转换为 JSON 嵌套格式。我可以轻松地将表导入 R。现在的问题是获取 JSON 格式的所有父子关系。我已经设法拥有某种 JSON 输出,但仅以以下形式列出所有具有各自孩子的父母个人:(我将仅列出表格的前 6 行)

[
  [
    {
      "name": ["a"],
      "children": ["b"]
    },
    {
      "name": ["b"],
      "children": ["c"]
    },
    {
      "name": ["c"],
      "children": ["d"]
    },
    {
      "name": ["b"],
      "children": ["e"]
    },
    {
      "name": ["e"],
      "children": ["f"]
    }
  ]
] 

library(RJSONIO)
orgTable=orgTable[,c("Manager","ID")]
makeList<-function(x){
    if(ncol(x)>2){
        listSplit = split(x[-1],x[1],drop=T)
        lapply(names(listSplit),function(y){list(name=y,children=makeList(listSplit[[y]]))})
    }
    else{
        lapply(seq(nrow(x[1])),function(y){list(name=x[,1][y],children=x[,2][y])})
    }
}

jsonOut = toJSON(list(makeList(orgTable[2:6,])),pretty=TRUE)
cat(jsonOut)

SQL 表是:

Parent     Children
a          b
b          c
c          d
b          e
e          f

我想要得到的会是这样的:

   {
    "name": "a",
    "children": [
        {
        "name": "b",
        "children": [
            {
            "name": "c",
            "children": [
                {
                "name": "d"
                }
                ]
            },
            {
            "name": "e",
            "children": [
                {
                "name": "f"
                }
                ]
            }
        ]
    }
    ]
}

有人可以帮忙吗?如果可能的话,如果我还可以添加第三列中的信息将是完美的。

我提供的代码来自this post,但根据我的需要进行了微调。 我还是 R 的新手,所以请多多包涵。

提前致谢

【问题讨论】:

    标签: sql json r nested


    【解决方案1】:

    我将从一个简单的递归解决方案开始,它只获取没有其他属性的父/子。

    #get some help from igraph
    library(igraph)
    
    df <- read.table(
      textConnection(
    '
    Parent     Children
    a          b
    b          c
    c          d
    b          e
    e          f
    ' )
      , header = TRUE
      , stringsAsFactors = FALSE
    )
    
    el_in <- get.adjlist(graph.data.frame(df),mode="in")
    # fill in name/id instead of number
    el_in <- lapply(
      el_in,
      function(x){
        names(el_in)[x]
      }
    )
    
    get_children <- function( adjlist, node ){
      names(Filter(function(x) x==node,unlist(el_in)))
    }
    
    recurse_tree <- function( adjlist, node = NULL ){
      #  start at root if undefined
      #    root will be the node with no in
      if(is.null(node)) node <- names(Filter(function(x)length(x)==0,adjlist))
    
      children <- get_children( adjlist, node )
      if(length(children)>0){
        list(
          name = node
          ,children = lapply(
            children
            ,function(x){
              recurse_tree( adjlist, x )
            }
          )
        )
      } else {
        list(
          name = node
        )
      }
    }
    
    
    jsonlite::toJSON(
      recurse_tree( el_in ),
      auto_unbox=T
    )
    

    可能不是最有效的,但这里有一个使用data.treeigraph 来构建我们的层次结构的解决方案。

    #get some help from the relatively new data.tree
    #devtools::install_github("gluc/data.tree")
    library(data.tree)
    #get some help from igraph
    library(igraph)
    
    df <- read.table(
      textConnection(
    '
    Parent     Children
    a          b
    b          c
    c          d
    b          e
    e          f
    ' )
      , header = TRUE
      , stringsAsFactors = FALSE
    )
    
    #this will be our paths for data.tree
    build_path <- function(df){
      g <- graph.data.frame(df)
      #get an adjacency list of all in
      el_in <- get.adjlist( g, mode="in" )
      tree <- lapply(el_in,function(x){""})
      lapply(
        1:length(el_in)
        ,function(n){
          id <- names(el_in)[n]
          x <- el_in[[n]]
          if(length(x)>0){
            tree[[id]] <<- paste0(
              tree[[el_in[[id]]]],
              "/",
              id
            )
          } else {
            tree[[id]] <<- id
          }
        }
      )
      return(unlist(tree))
    }
    
    
    tree <- as.Node(data.frame(
      pathString = build_path(df),
      # have the ability to specify values
      #  if not then just set NA
      value = NA,
      stringsAsFactors = F
    ))
    
    jsonlite::toJSON(
      as.list( tree, mode="explicit", unname = TRUE),
      auto_unbox = TRUE
    )
    
    # as a test let's build a random tree with igraph
    tree_grf <- graph.tree(n=10,children=3)
    plot(tree_grf)
    tree <- as.Node(data.frame(
      pathString = build_path(
        get.data.frame(tree_grf,what="edges")
      ),
      # have the ability to specify values
      #  if not then just set NA
      value = NA,
      stringsAsFactors = F
    ))
    

    【讨论】:

    • 感谢您的快速回复@timelyportfolio。我正在尝试运行您的代码,但我可能缺少一个包,因为我收到以下错误:错误:找不到函数“as.Node”和错误:没有方法 asJSON S3 类:名称
    • 你必须做devtools::install_github("gluc/data.tree")。如果您没有devtools,请查看github.com/hadley/…
    • 安装data.tree包后,我加载包并通过仅运行library(data.tree)得到:Error : cannot allocate vector of size 2.8 Gb
    • 我将在我的答案中添加一个非 data.tree 解决方案。
    • 它正在工作!!!我必须从 github 安装 Rtools,现在它可以工作了 :) 非常感谢,我非常感谢您的快速回复。
    猜你喜欢
    • 2010-09-29
    • 2017-11-12
    • 2022-01-18
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    • 2022-01-24
    • 2016-04-20
    • 1970-01-01
    相关资源
    最近更新 更多