0

Let's say I have the following integer matrix in Dart:

final List<List<int>> myMatrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

Then I try to store it in Cloud Firestore like this:

await Firestore.instance.collection("anyCollection").add({
    "matrix" : myMatrix,
});

But as soon as I run the code above, the simulator crashes and I get the following error:

*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff23c4f02e __exceptionPreprocess + 350
    1   libobjc.A.dylib                     0x00007fff50b97b20 objc_exception_throw + 48
    2   Runner                              0x000000010e83f8b5 _ZN8firebase9firestore4util16ObjcThrowHandlerENS1_13ExceptionTypeEPKcS4_iRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE + 581
    3   Runner                              0x000000010e83edf3 _ZN8firebase9firestore4util5ThrowENS1_13ExceptionTypeEPKcS4_iRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE + 67
    4   Runner                              0x000000010e890589 _ZN8firebase9firestore4util20ThrowInvalidArgumentIJEEEvPKcDpRKT_ + 57
    5   Runner                              0x000000010e959f65 -[FSTUserDataConverter parseData:context:] + 1045
    6   Runner                              0x000000010e<…>
Lost connection to device.

I am running cloud_firestore: ^0.13.0+1 (currently the latest version) in the pubspec.yaml file. Everything is fine when running the flutter doctor command as well.

What am I doing wrong? Is it even possible to store matrixes in Firestore? If not, can I store that data using another logic?

ThiagoAM
  • 1,432
  • 13
  • 20
  • From my experience, you cannot store array or arrays in firestore, however you can serialize array into either multiple rows, each row is a field, or multiple columns, each columns is a field. – dlohani Jan 02 '20 at 08:43

3 Answers3

2

While you can store an array in Firestore, as mentioned in the documentation, you are not allowed to store another array inside it.

You could take an approach where you store the arrays as fields in a document so you can actually keep each array separated. This is shown over at this thread, or this one.

Hope you find this useful!

rsalinas
  • 1,507
  • 8
  • 9
0

The following approach will work for the Matrix you gave as an example, but you won't be able to query the matrix directly from Firestore. You must take the whole matrix out, parse it, and then use it:

final List<List<int>> myMatrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

// Encode your matrix into a JSON String to add to Firestore
String jsonMatrix = jsonEncode(myMatrix);

// Decode your Json String into a JSON object
var decodedMatrix = jsonDecode(jsonMatrix);

// Decode JSON object back into your matrix
List<List<int>> newList = List<List<int>>.from(decodedMatrix.map((row){
  return List<int>.from(row.map((value) => int.parse(value.toString())));
}));

// Print to show that the new object is of the same type as the original Matrix
print(newList is List<List<int>>);
halfer
  • 19,824
  • 17
  • 99
  • 186
J. S.
  • 8,905
  • 2
  • 34
  • 44
0

I ended up making the following helper that converts the matrix into a map that's compatible with Firestore:

class MatrixHelper {

  // Creates a map that can be stored in Firebase from an int matrix.
  static Map<String, dynamic> mapFromIntMatrix(List<List<int>> intMatrix) {
    Map<String, Map<String, dynamic>> map = {};
    int index = 0;
    for (List<int> row in intMatrix) {
      map.addEntries([MapEntry(index.toString(), {})]);
      for (int value in row) {
        map[index.toString()].addEntries(
            [MapEntry(value.toString(), true)]
        );
      }
      index += 1;
    }
    return map;
  }

  // Creates an int matrix from a dynamic map.
  static List<List<int>> intMatrixFromMap(Map<dynamic, dynamic> dynamicMap) {
    final map = Map<String, dynamic>.from(dynamicMap);
    List<List<int>> matrix = [];
    map.forEach((stringIndex, value) {
      Map<String, dynamic> rowMap = Map<String, dynamic>.from(value);
      List<int> row = [];
      rowMap.forEach((stringNumber, boolean) {
        row.add(int.parse(stringNumber));
      });
      matrix.add(row);
    });
    return matrix;
  }

}

It's really simple to use, to save in Firestore it's like this:

final List<List<int>> myMatrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

await Firestore.instance.collection("anyCollection").add({
    "matrix" : MatrixHelper.mapFromIntMatrix(myMatrix),
});

To load the matrix from Firestore, it's like this:

// Loads the DocumentSnapshot:
final document = await Firestore.instance.collection("anyCollection").document("anyDocument").get();
// Retrieves the Matrix:
final List<List<int>> matrix = MatrixHelper.intMatrixFromMap(document.data["matrix"]);
ThiagoAM
  • 1,432
  • 13
  • 20