首页 > 其他分享 >golang用pgx查询数据时如何将查询结果方便的放入Map中

golang用pgx查询数据时如何将查询结果方便的放入Map中

时间:2023-08-03 09:01:47浏览次数:45  
标签:Map rows return nil err map 查询 golang pgx

pgx库简介

下面是来自官网的简介: pgx - PostgreSQL驱动和工具包

pgx是一个用于PostgreSQL的纯Go语言驱动和工具包。

pgx驱动是一个底层的高性能接口,暴露了PostgreSQL特有的功能,如LISTEN/NOTIFYCOPY。它还包含一个标准database/sql接口的适配器。

工具包组件是一组相关的包,实现了像解析wire协议和PostgreSQL与Go之间的类型映射等PostgreSQL功能。这些底层包可用于实现替代驱动、代理、负载均衡器、逻辑复制客户端等。

pgx应该是目前最好的启动包了,“pg” 另一个著名的PostgreSQL启动包的状态目前仅仅是维护了,并且推荐了pgx。

"对于需要新功能或可靠解决报告中的错误的用户,我们推荐使用正在积极开发中的pgx。" -pq维护人员

pgx比较底层,没有ORM的功能,比如我要将一行查询结果扫描到一个Map中。

近期由于开发一个pg到elastic的复制工具(包括wal增量复制和全量复制),在实现全量复制时,我需要将一行查询结果放到Map中,结果尴尬了,pgx中竟然没有这样的功能,难道我要因此使用gorm或者xorm(虽然也很方便,但是多引入一个包我也不那么愿意),经过询问必应,只得到了,自己声明一堆和字段对应变量然后扫描这样的例子:

 ​
 // RetreiveBook
 func RetreiveBook(db *sql.DB) ([]Book, error) {
    var books []Book
    // 查询
    sql := `select book_id, title, author, to_char(publish_date, 'YYYY/MM/DD') as publish_date from m_book`
    rows, err := db.Query(sql)
    if err != nil {
       log.Println(err)
       return books, err
    }
    defer rows.Close()
 ​
    for rows.Next() {
       var book Book
       // 获取各列的值,放到对应的地址中
       rows.Scan(&book.BookId, &book.Title, &book.Author, &book.PublishDate)
       books = append(books, book)
    }
 ​
    return books, nil
 }
 ​

太麻烦了,我忍不了。

pgx有内置的方法

于是我不甘心的仔细查看pgx的文档和实例,终于,我发现了这个方法:

 func pgx.CollectRows(rows pgx.Rows, fn pgx.RowToFunc[map[string]any]) ([]map[string]any, error)
 // func[T any](rows pgx.Rows, fn pgx.RowToFunc[T]) ([]T, error)
 // CollectRows iterates through rows, calling fn for each row, and collecting the results into a slice of T.

但是显然,这个方法是一次性的生成一个map的切片,如果数据量不大还好,但是对于我要用到的全量复制场景就未免不适合了,但是只要有了方向就好了,赶紧跟踪进去,

 // CollectRows iterates through rows, calling fn for each row, and collecting the results into a slice of T.
 func CollectRows[T any](rows Rows, fn RowToFunc[T]) ([]T, error) {
  defer rows.Close()
 ​
  slice := []T{}
 ​
  for rows.Next() {
  value, err := fn(rows)
  if err != nil {
  return nil, err
  }
  slice = append(slice, value)
  }
 ​
  if err := rows.Err(); err != nil {
  return nil, err
  }
 ​
  return slice, nil
 }

可见上述代码中,仅仅是简单的Next() Scan()然后回调pgx.RowToMap这个函数生成map,我不需要它一次性地给我map的切片,但是我可以轻松将他实现的过程移植到我的代码中,至此问题完美解决了。至于pgx.RowToMap这个方法的实现,其实非常简单,下面就是其源代码:

 // RowToMap returns a map scanned from row.
 func RowToMap(row CollectableRow) (map[string]any, error) {
  var value map[string]any
  err := row.Scan((*mapRowScanner)(&value))
  return value, err
 }
 ​
 type mapRowScanner map[string]any
 ​
 func (rs *mapRowScanner) ScanRow(rows Rows) error {
  values, err := rows.Values()
  if err != nil {
  return err
  }
 ​
  *rs = make(mapRowScanner, len(values))
 ​
  for i := range values {
  (*rs)[string(rows.FieldDescriptions()[i].Name)] = values[i]
  }
 ​
  return nil
 }

其中19行就是这个属性方法rows.FieldDescriptions()我不知道,否则自己也可以方便地实现扫描到map的方法了。

标签:Map,rows,return,nil,err,map,查询,golang,pgx
From: https://www.cnblogs.com/dajianshi/p/17602344.html

相关文章

  • 16.map插入方式有哪几种?
    16.map插入方式有哪几种?1.用insert函数插入pair数据mapStudent.insert(pair<int,string>(1,"student_one"));2.用insert函数插入value_type数据mapStudent.insert(map<int,string>::value_type(1,"student_one"));3.在insert函数中使用make_pair()函数mapStu......
  • 17.STL中unordered_map(hash_map)和map的区别,hash_map如何解决冲突以及扩容
    17.STL中unordered_map(hash_map)和map的区别,hash_map如何解决冲突以及扩容1.区别1.1需要引入的头文件不同map:#include<map>unordered_map:#include<unordered_map>1.2内部实现机理不同map:map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二......
  • 18.vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间?
    18.vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间?1.vector越界访问下标std::vector是C++标准库中的一种动态数组,其大小可以根据需要进行调整。当你试图访问一个不存在的元素,即访问超出其当前大小范围的索引时,将会发生越界访问。在C++中,如果你使用operator[......
  • 19.map中[]与find的区别?
    19.map中[]与find的区别?map的下标运算符[]的作用是:将关键码作为下标去执行查找,并返回对应的值;如果不存在这个关键码,就将一个具有该关键码和值类型的默认值的项插入这个map。map的find函数:用关键码执行查找,找到了返回该位置的迭代器;如果不存在这个关键码,就返回尾迭代器。......
  • Golang反射type和kind有什么区
    一、前言Go语言中的反射是由reflect包提供支持的,它定义了两个重要的类型Type和Value。任意值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。在Go语......
  • 模版层、模型层(modle)、外键字段查询、环境测试搭建、基于下划线查询
    模版之标签模版里面使流程控制:if、else、elseif、for标签:{%tag%}for标签 后端代码deftag(request):user_list=[1,2,3]returnrender(request,'tag.html',locals())前端代码<body>{%foruserinuser_list%}{{user}}{%endfor%}</bo......
  • 仅三天,我用 GPT-4 生成了性能全网第一的 Golang Worker Pool,轻松打败 GitHub 万星项目
    目录1.我写了一个超牛的开源项目1.1你看看这性能1.2你看看这功能1.3你猜我这一百天都经历了啥2.你有多久没写并发程序了?3.问:一个WorkerPool程序需要包含哪些功能?4.让GPT-4写第一行代码!4.1我对GPT-4说4.2GPT-4回答4.3我又对GPT-4说4.4GPT-4给出了新的回答4.5......
  • golang json字符串转结构体
    1、不知道结构体类型的情况下funcJsonStringToMap(jsonStrstring)(map[string]interface{},error){//未知值类型m:=make(map[string]interface{})err:=json.Unmarshal([]byte(jsonStr),&m)iferr!=nil{fmt.Printf("Unmarshalwither......
  • mybatisplus 查询结果排除某字段实现
    数据有Test表,表里有id,name,ip_address,last_time四个字段通常查询写法,返回结果会把id,name,ip_address,last_time四个字段都返回publicListselectList(Testtest){Listlist=testMapper.selectList(newQueryWrapper<>(test))returnlist;}现在想排......
  • 员工分页查询_代码完善
           ......