Hàm mảng

Hàm mảng

Tên Mô tả
ARRAY Trả về một ARRAY chứa một phần tử cho mỗi đối số đầu vào
ARRAY_CONCAT Nối nhiều mảng thành một mảng duy nhất ARRAY
ARRAY_CONTAINS Trả về TRUE nếu một ARRAY nhất định chứa một giá trị cụ thể
ARRAY_CONTAINS_ALL Trả về TRUE nếu tất cả giá trị đều có trong ARRAY
ARRAY_CONTAINS_ANY Trả về TRUE nếu có giá trị nào trong ARRAY
ARRAY_FILTER Lọc bỏ các phần tử khỏi một ARRAY không đáp ứng một vị từ
ARRAY_FIRST Trả về phần tử đầu tiên trong ARRAY
ARRAY_FIRST_N Trả về n phần tử đầu tiên trong ARRAY
ARRAY_GET Trả về phần tử tại một chỉ mục nhất định trong ARRAY
ARRAY_INDEX_OF Trả về chỉ mục của lần xuất hiện đầu tiên của một giá trị trong ARRAY
ARRAY_INDEX_OF_ALL Trả về tất cả chỉ mục của một giá trị trong ARRAY
ARRAY_LENGTH Trả về số lượng phần tử trong một ARRAY
ARRAY_LAST Trả về phần tử cuối cùng trong ARRAY
ARRAY_LAST_N Trả về n phần tử cuối cùng trong một ARRAY
ARRAY_REVERSE Đảo ngược thứ tự của các phần tử trong ARRAY
ARRAY_SLICE Trả về một lát cắt của ARRAY
ARRAY_TRANSFORM Biến đổi các phần tử trong ARRAY bằng cách áp dụng biểu thức cho từng phần tử
MAXIMUM Trả về giá trị lớn nhất trong một ARRAY
MAXIMUM_N Trả về n giá trị lớn nhất trong một ARRAY
MINIMUM Trả về giá trị nhỏ nhất trong một ARRAY
MINIMUM_N Trả về n giá trị nhỏ nhất trong một ARRAY
SUM Trả về tổng của tất cả các giá trị NUMERIC trong một ARRAY.
JOIN Tạo ra một chuỗi nối các phần tử trong ARRAY dưới dạng giá trị STRING.

MẢNG

Cú pháp:

array(values: ANY...) -> ARRAY

Nội dung mô tả:

Tạo một mảng từ các phần tử đã cho.

  • Nếu không có đối số, đối số đó sẽ được thay thế bằng NULL trong mảng kết quả.

Ví dụ:

giá trị array(values)
() []
(1, 2, 3) [1, 2, 3]
("a", 1, true) ["a", 1, true]
(1, null) [1, null]
(1; [2; 3]) [1, [2, 3]]

Hàm ARRAY_CONCAT

Cú pháp:

array_concat(arrays: ARRAY...) -> ARRAY

Nội dung mô tả:

Nối hai hoặc nhiều mảng thành một ARRAY duy nhất.

Ví dụ:

mảng array_concat(arrays)
([1, 2], [3, 4]) [1, 2, 3, 4]
(["a", "b"], ["c"]) ["a", "b", "c"]
([1], [2], [3]) [1, 2, 3]
([], [1, 2]) [1, 2]
Node.js
const result = await db.pipeline()
  .collection("books")
  .select(field("genre").arrayConcat([field("subGenre")]).as("allGenres"))
  .execute();
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([Field("genre").arrayConcat([Field("subGenre")]).as("allGenres")])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayConcat(field("subGenre")).alias("allGenres"))
    .execute()

Java

Task<Pipeline.Snapshot> result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayConcat(field("subGenre")).alias("allGenres"))
    .execute();
    
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(Field.of("genre").array_concat(Field.of("subGenre")).as_("allGenres"))
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(arrayConcat(field("genre"), field("subGenre")).as("allGenres"))
        .execute()
        .get();

ARRAY_CONTAINS

Cú pháp:

array_contains(array: ARRAY, value: ANY) -> BOOLEAN

Nội dung mô tả:

Trả về TRUE nếu tìm thấy value trong array, và FALSE trong trường hợp ngược lại.

Ví dụ:

mảng value array_contains(array, value)
[1, 2, 3] 2 đúng
[[1, 2], [3]] [1, 2] đúng
[1, null] null đúng
"abc" BẤT KỲ error
Node.js
const result = await db.pipeline()
  .collection("books")
  .select(field("genre").arrayContains(constant("mystery")).as("isMystery"))
  .execute();

Web

const result = await execute(db.pipeline()
  .collection("books")
  .select(field("genre").arrayContains(constant("mystery")).as("isMystery"))
);
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([Field("genre").arrayContains(Constant("mystery")).as("isMystery")])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayContains("mystery").alias("isMystery"))
    .execute()

Java

Task<Pipeline.Snapshot> result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayContains("mystery").alias("isMystery"))
    .execute();
    
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(Field.of("genre").array_contains("mystery").as_("isMystery"))
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(arrayContains(field("genre"), "mystery").as("isMystery"))
        .execute()
        .get();

ARRAY_CONTAINS_ALL

Cú pháp:

array_contains_all(array: ARRAY, search_values: ARRAY) -> BOOLEAN

Nội dung mô tả:

Trả về TRUE nếu tìm thấy tất cả search_values trong arrayFALSE trong trường hợp ngược lại.

Ví dụ:

mảng search_values array_contains_all(array, search_values)
[1, 2, 3] [1, 2] đúng
[1, 2, 3] [1, 4] false
[1, null] [không] đúng
[NaN] [NaN] đúng
[] [] đúng
[1, 2, 3] [] đúng
Node.js
const result = await db.pipeline()
  .collection("books")
  .select(
    field("genre")
      .arrayContainsAll([constant("fantasy"), constant("adventure")])
      .as("isFantasyAdventure")
  )
  .execute();

Web

const result = await execute(db.pipeline()
  .collection("books")
  .select(
    field("genre")
      .arrayContainsAll([constant("fantasy"), constant("adventure")])
      .as("isFantasyAdventure")
  )
);
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([
    Field("genre")
      .arrayContainsAll([Constant("fantasy"), Constant("adventure")])
      .as("isFantasyAdventure")
  ])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(
        field("genre")
            .arrayContainsAll(listOf("fantasy", "adventure"))
            .alias("isFantasyAdventure")
    )
    .execute()

Java

Task<Pipeline.Snapshot> result = db.pipeline()
    .collection("books")
    .select(
        field("genre")
            .arrayContainsAll(Arrays.asList("fantasy", "adventure"))
            .alias("isFantasyAdventure")
    )
    .execute();
    
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(
        Field.of("genre")
        .array_contains_all(["fantasy", "adventure"])
        .as_("isFantasyAdventure")
    )
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(
            arrayContainsAll(field("genre"), Arrays.asList("fantasy", "adventure"))
                .as("isFantasyAdventure"))
        .execute()
        .get();

Hàm ARRAY_CONTAINS_ANY

Cú pháp:

array_contains_any(array: ARRAY, search_values: ARRAY) -> BOOLEAN

Nội dung mô tả:

Trả về TRUE nếu tìm thấy bất kỳ search_values nào trong array, và FALSE trong trường hợp ngược lại.

Ví dụ:

mảng search_values array_contains_any(array, search_values)
[1, 2, 3] [4, 1] đúng
[1, 2, 3] [4, 5] false
[1, 2, null] [không] đúng
Node.js
const result = await db.pipeline()
  .collection("books")
  .select(
    field("genre")
      .arrayContainsAny([constant("fantasy"), constant("nonfiction")])
      .as("isMysteryOrFantasy")
  )
  .execute();

Web

const result = await execute(db.pipeline()
  .collection("books")
  .select(
    field("genre")
      .arrayContainsAny([constant("fantasy"), constant("nonfiction")])
      .as("isMysteryOrFantasy")
  )
);
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([
    Field("genre")
      .arrayContainsAny([Constant("fantasy"), Constant("nonfiction")])
      .as("isMysteryOrFantasy")
  ])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(
        field("genre")
            .arrayContainsAny(listOf("fantasy", "nonfiction"))
            .alias("isMysteryOrFantasy")
    )
    .execute()

Java

Task<Pipeline.Snapshot> result = db.pipeline()
    .collection("books")
    .select(
        field("genre")
            .arrayContainsAny(Arrays.asList("fantasy", "nonfiction"))
            .alias("isMysteryOrFantasy")
    )
    .execute();
    
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(
        Field.of("genre")
        .array_contains_any(["fantasy", "nonfiction"])
        .as_("isMysteryOrFantasy")
    )
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(
            arrayContainsAny(field("genre"), Arrays.asList("fantasy", "nonfiction"))
                .as("isMysteryOrFantasy"))
        .execute()
        .get();

Hàm ARRAY_FILTER

Cú pháp:

array_filter(array: ARRAY, predicate: (ANY) -> BOOLEAN) -> ARRAY

Nội dung mô tả:

Lọc array bằng biểu thức predicate, trả về một mảng mới chỉ chứa các phần tử đáp ứng vị từ.

  • Đối với mỗi phần tử trong array, predicate sẽ được đánh giá. Nếu trả về true, phần tử sẽ được đưa vào kết quả; nếu không (nếu trả về false hoặc null), phần tử sẽ bị bỏ qua.
  • Nếu predicate đánh giá thành một giá trị không phải là giá trị Boolean hoặc giá trị không rỗng, thì hàm sẽ trả về lỗi.

Ví dụ:

mảng vị từ array_filter(array, predicate)
[1, 2, 3] x -> x > 1 [2, 3]
[1, null, 3] x -> x > 1 [3]
["a", "b", "c"] x -> x != "b" ["a", "c"]
[] x -> true []

Hàm ARRAY_GET

Cú pháp:

array_get(array: ARRAY, index: INT64) -> ANY

Nội dung mô tả:

Trả về phần tử tại index dựa trên 0 trong array.

  • Nếu index là số âm, các phần tử sẽ được truy cập từ cuối mảng, trong đó -1 là phần tử cuối cùng.
  • Nếu array không thuộc kiểu ARRAY và không phải là null, hàm sẽ trả về lỗi.
  • Nếu index nằm ngoài phạm vi, hàm sẽ trả về một giá trị không có.
  • Nếu index không thuộc kiểu INT64, hàm sẽ trả về lỗi.

Ví dụ:

mảng index array_get(array, index)
[1, 2, 3] 0 1
[1, 2, 3] -1 3
[1, 2, 3] 3 vắng mặt
[1, 2, 3] -4 vắng mặt
"abc" 0 error
null 0 null
Array "a" error
Array 2.0 error

Hàm ARRAY_LENGTH

Cú pháp:

array_length(array: ARRAY) -> INT64

Nội dung mô tả:

Trả về số lượng phần tử trong array.

Ví dụ:

mảng array_length(array)
[1, 2, 3] 3
[] 0
[1, 1, 1] 3
[1, null] 2
Node.js
const result = await db.pipeline()
  .collection("books")
  .select(field("genre").arrayLength().as("genreCount"))
  .execute();

Web

const result = await execute(db.pipeline()
  .collection("books")
  .select(field("genre").arrayLength().as("genreCount"))
);
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([Field("genre").arrayLength().as("genreCount")])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayLength().alias("genreCount"))
    .execute()

Java

Task<Pipeline.Snapshot> result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayLength().alias("genreCount"))
    .execute();
    
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(Field.of("genre").array_length().as_("genreCount"))
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(arrayLength(field("genre")).as("genreCount"))
        .execute()
        .get();

Hàm ARRAY_REVERSE

Cú pháp:

array_reverse(array: ARRAY) -> ARRAY

Nội dung mô tả:

Đảo ngược array đã cho.

Ví dụ:

mảng array_reverse(array)
[1, 2, 3] [3, 2, 1]
["a", "b"] ["b", "a"]
[1, 2, 2, 3] [3, 2, 2, 1]
Node.js
const result = await db.pipeline()
  .collection("books")
  .select(arrayReverse(field("genre")).as("reversedGenres"))
  .execute();

Web

const result = await execute(db.pipeline()
  .collection("books")
  .select(field("genre").arrayReverse().as("reversedGenres"))
);
Swift
let result = try await db.pipeline()
  .collection("books")
  .select([Field("genre").arrayReverse().as("reversedGenres")])
  .execute()

Kotlin

val result = db.pipeline()
    .collection("books")
    .select(field("genre").arrayReverse().alias("reversedGenres"))
    .execute()
    

Java

Task<Pipeline.Snapshot> result = db.pipeline() .collection("books") .select(field("genre").arrayReverse().alias("reversedGenres")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

result = (
    client.pipeline()
    .collection("books")
    .select(Field.of("genre").array_reverse().as_("reversedGenres"))
    .execute()
)
Java
Pipeline.Snapshot result =
    firestore
        .pipeline()
        .collection("books")
        .select(arrayReverse(field("genre")).as("reversedGenres"))
        .execute()
        .get();

Hàm ARRAY_FIRST

Cú pháp:

array_first(array: ARRAY) -> ANY

Nội dung mô tả:

Trả về phần tử đầu tiên trong array. Điều này tương đương với array_get(array, 0).

  • Nếu array là giá trị trống, hàm sẽ trả về một giá trị không có.

Ví dụ:

mảng array_first(array)
[1, 2, 3] 1
[] vắng mặt

Hàm ARRAY_FIRST_N

Cú pháp:

array_first_n(array: ARRAY, n: INT64) -> ARRAY

Nội dung mô tả:

Trả về n phần tử đầu tiên của array. Điều này tương đương với array_slice(array, 0, n).

  • Nếu n là số âm, hàm sẽ trả về lỗi.

Ví dụ:

mảng n array_first_n(array, n)
[1, 2, 3, 4, 5] 3 [1, 2, 3]
[1, 2] 3 [1, 2]
[1, 2, 3] 0 []

Hàm ARRAY_INDEX_OF

Cú pháp:

array_index_of(array: ARRAY, value: ANY) -> INT64

Nội dung mô tả:

Trả về chỉ mục dựa trên 0 của lần xuất hiện đầu tiên của value trong array. Trả về -1 nếu không tìm thấy value.

Ví dụ:

mảng value array_index_of(array, value)
[1, 2, 3, 2] 2 1
[1, 2, 3] 4 -1
[1, null, 3] null 1

ARRAY_INDEX_OF_ALL

Cú pháp:

array_index_of_all(array: ARRAY, value: ANY) -> ARRAY<INT64>

Nội dung mô tả:

Trả về một mảng chứa các chỉ mục từ 0 của tất cả các lần xuất hiện value trong array. Trả về [] nếu không tìm thấy value.

Ví dụ:

mảng value array_index_of_all(array, value)
[1, 2, 3, 2] 2 [1, 3]
[1, 2, 3] 4 []
[1, null, 3, null] null [1, 3]

Hàm ARRAY_LAST

Cú pháp:

array_last(array: ARRAY) -> ANY

Nội dung mô tả:

Trả về phần tử cuối cùng trong array. Điều này tương đương với array_get(array, -1).

  • Nếu array là giá trị trống, hàm sẽ trả về một giá trị không có.

Ví dụ:

mảng array_last(array)
[1, 2, 3] 3
[] vắng mặt

Hàm ARRAY_LAST_N

Cú pháp:

array_last_n(array: ARRAY, n: INT64) -> ARRAY

Nội dung mô tả:

Trả về n phần tử cuối cùng của array.

  • Nếu n là số âm, hàm sẽ trả về lỗi.

Ví dụ:

mảng n array_last_n(array, n)
[1, 2, 3, 4, 5] 3 [3, 4, 5]
[1, 2] 3 [1, 2]
[1, 2, 3] 0 []

Hàm ARRAY_SLICE

Cú pháp:

array_slice(array: ARRAY, offset: INT64, length: INT64) -> ARRAY

Nội dung mô tả:

Trả về một tập hợp con của array, bắt đầu từ chỉ mục offset dựa trên 0 và bao gồm length phần tử.

  • Nếu offset là số âm, thì đó là vị trí bắt đầu từ cuối mảng, trong đó -1 là phần tử cuối cùng.
  • Nếu length lớn hơn số phần tử còn lại trong mảng sau offset, thì kết quả sẽ kéo dài đến cuối mảng.
  • length phải là số không âm, nếu không sẽ trả về lỗi.

Ví dụ:

mảng độ lệch chiều dài array_slice(array, offset, length)
[1, 2, 3, 4, 5] 1 3 [2, 3, 4]
[1, 2, 3, 4, 5] -2 2 [4, 5]
[1, 2, 3] 1 5 [2, 3]
[1, 2, 3] 3 2 []

Hàm ARRAY_TRANSFORM

Cú pháp:

array_transform(array: ARRAY, expression: (ANY) -> ANY) -> ARRAY
array_transform(array: ARRAY, expression: (ANY, INT64) -> ANY) -> ARRAY

Nội dung mô tả:

Biến đổi array bằng cách áp dụng expression cho từng phần tử, trả về một mảng mới có các phần tử đã biến đổi. Dãy đầu ra sẽ luôn có cùng kích thước với dãy đầu vào.

  • expression có thể là hàm một ngôi element -> result hoặc hàm hai ngôi (element, index) -> result.
  • Nếu expression là đơn nguyên, thì hàm này sẽ được gọi với từng phần tử của array.
  • Nếu expression là nhị phân, thì hàm này sẽ được gọi với từng phần tử của array và chỉ mục tương ứng dựa trên 0 của phần tử đó.

Ví dụ:

mảng biểu thức array_transform(array, expression)
[1, 2, 3] x -> x * 2 [2, 4, 6]
[1, 2, 3] x -> x + 1 [2, 3, 4]
[10, 20] (x, i) -> x + i [10, 21]
[] x -> 1 []

TỐI ĐA

Cú pháp:

maximum(array: ARRAY) -> ANY

Nội dung mô tả:

Trả về giá trị lớn nhất trong array.

  • Các giá trị NULL sẽ bị bỏ qua trong quá trình so sánh.
  • Nếu array trống hoặc chỉ chứa các giá trị NULL, thì hàm sẽ trả về NULL.

Ví dụ:

mảng maximum(array)
[1, 5, 2] 5
[1, null, 5] 5
["a", "c", "b"] "c"
[null, null] null
[] null

MAXIMUM_N

Cú pháp:

maximum_n(array: ARRAY, n: INT64) -> ARRAY

Nội dung mô tả:

Trả về một mảng gồm n giá trị lớn nhất trong array theo thứ tự giảm dần.

  • Các giá trị của NULL sẽ bị bỏ qua.
  • Nếu n là số âm, hàm sẽ trả về lỗi.

Ví dụ:

mảng n maximum_n(array, n)
[1, 5, 2, 4, 3] 3 [5, 4, 3]
[1, null, 5] 3 [5, 1]

TỐI THIỂU

Cú pháp:

minimum(array: ARRAY) -> ANY

Nội dung mô tả:

Trả về giá trị nhỏ nhất trong array.

  • Các giá trị NULL sẽ bị bỏ qua trong quá trình so sánh.
  • Nếu array trống hoặc chỉ chứa các giá trị NULL, thì hàm sẽ trả về NULL.

Ví dụ:

mảng minimum(array)
[1, 5, 2] 1
[5, null, 1] 1
["a", "c", "b"] "a"
[null, null] null
[] null

MINIMUM_N

Cú pháp:

minimum_n(array: ARRAY, n: INT64) -> ARRAY

Nội dung mô tả:

Trả về một mảng gồm n giá trị nhỏ nhất trong array theo thứ tự tăng dần.

  • Các giá trị của NULL sẽ bị bỏ qua.
  • Nếu n là số âm, hàm sẽ trả về lỗi.

Ví dụ:

mảng n minimum_n(array, n)
[1, 5, 2, 4, 3] 3 [1, 2, 3]
[5, null, 1] 3 [1, 5]

SUM

Cú pháp:

sum(array: ARRAY) -> INT64 | FLOAT64

Nội dung mô tả:

Trả về tổng của tất cả các giá trị NUMERIC trong một ARRAY.

  • Các giá trị không phải là số trong mảng sẽ bị bỏ qua.
  • Nếu có giá trị số nào trong mảng là NaN, thì hàm sẽ trả về NaN.
  • Kiểu dữ liệu trả về được xác định bằng loại số rộng nhất trong mảng: INT64 < FLOAT64.
  • Nếu xảy ra tràn số nguyên 64 bit trước khi bất kỳ giá trị dấu phẩy động nào được cộng, thì một lỗi sẽ được trả về. Nếu các giá trị dấu phẩy động được cộng lại, thì tình trạng tràn sẽ dẫn đến kết quả là +/- vô cực.
  • Nếu mảng không chứa giá trị số nào, hàm sẽ trả về NULL.

Ví dụ:

mảng sum(array)
[1, 2, 3] 6L
[1L, 2L, 3L] 6L
[2000000000, 2000000000] 4000000000L
[10, 20.5] 30,5
[1, "a", 2] 3L
[INT64.MAX_VALUE, 1] error
[INT64.MAX_VALUE, 1, -1.0] error
[INT64.MAX_VALUE, 1.0] 9,223372036854776e+18

THAM GIA

Cú pháp:

join[T <: STRING | BYTES](array: ARRAY<T>, delimiter: T) -> STRING
join[T <: STRING | BYTES](array: ARRAY<T>, delimiter: T, null_text: T) -> STRING

Nội dung mô tả:

Trả về chuỗi kết hợp của các phần tử trong array dưới dạng STRING. array có thể thuộc kiểu dữ liệu STRING hoặc BYTES.

  • Tất cả các phần tử trong array, delimiternull_text phải thuộc cùng một loại; tất cả đều phải là STRING hoặc tất cả đều phải là BYTES.
  • Nếu bạn cung cấp null_text, mọi giá trị NULL trong array sẽ được thay thế bằng null_text.
  • Nếu bạn không cung cấp null_text, thì các giá trị NULL trong array sẽ bị loại khỏi kết quả.

Ví dụ:

Khi bạn không cung cấp null_text:

mảng dấu phân cách join(array, delimiter)
["a", "b", "c"] "," "a,b,c"
["a", null, "c"] "," "a,c"
[b'a', b'b', b'c'] b',' b'a,b,c'
["a", b'c'] "," error
["a", "c"] b',' error
[b'a', b'c'] "," error

Khi bạn cung cấp null_text:

mảng dấu phân cách null_text join(array, delimiter, null_text)
["a", null, "c"] "," "MISSING" "a,MISSING,c"
[b'a', null, b'c'] b',' b'NULL' b'a,NULL,c'
[null, "b", null] "," "MISSING" "MISSING,b,MISSING"
[b'a', null, null] b',' b'NULL' b'a,NULL,NULL'
["a", null] "," b'N' error
[b'a', null] b',' "N" error