Rudiksz / couchbase_lite_dart

Dart implementation of the Couchbase Lite, an embedded, NoSQL JSON Document Style database.
BSD 3-Clause "New" or "Revised" License
24 stars 3 forks source link

Can not set properties when about to update a document #6

Closed richard457 closed 3 years ago

richard457 commented 3 years ago

tried this code

Document doc = db.getMutableDocument('1');

    Document mutdoc = doc.mutableCopy;
    mutdoc.properties  = {'name': 'another'} ;
db.saveDocument(doc);

and this:

 Document doc = db.getMutableDocument( '1');

    // Document mutdoc = doc.mutableCopy;

    doc.properties  = {'name': 'another'} ;
db.saveDocument(doc);

And they give the following error before I save the document A Value of type 'Map<String,String>' can't be assigned to a variable of type FLDict

Rudiksz commented 3 years ago

document.properties uses the Fleece API(FLValue, FLDict, FLArray) of couchbase lite C, use document.jsonProperties to get/set properties as Dart maps.

Edit: doc.getMutableDocument already returns a mutable document, so Document mutdoc = doc.mutableCopy; is not needed,

richard457 commented 3 years ago

Thanks, I updated the documentation and Sent a PR here https://github.com/Rudiksz/couchbase_lite_dart/pull/7

richard457 commented 3 years ago

Another issue found while testing is that doc.jsonProperties = {'name': 'Meem','table':'users'} ; need exact same properties as original document in order to updated! my first gues was if the document was like {'name':richie','table':'users','email':'b@gmail.com'} I would only update one field without necessarily explicitly pass all the properties like doc.jsonProperties = {'name': 'Murag'} just to update only name.

Rudiksz commented 3 years ago

Couchbase lite itself doesn't support subdocument operations, to modify single properties in-place you can use the fleece API Fleece is quite powerful and blazing fast, but it doesn't play well with Flutter and reactive models (I use mobx).

What I do is to have plain Dart data classes and parse the couchbase document like it was a json value (using the Fleece API), and when I'm ready to save it I just turn it into a Couchbase Document which then I save. Here's an example.

Unless you save really large documents and your write operations are substantially more than your read operations, performance is a non issue. Eventually the choice is yours depending on your needs.

class Character {
  final String id;
  final String name;
  final String description;
  final Map<CharacterStat, List<int>> stats;
  final List<Skill> skills;
  final bool remote;

  const Character({
    this.id,
    this.name,
    this.description,
    this.stats,
    this.skills,
    this.remote = false,
  });

  factory Character.fromDocument(Document doc) =>
      Character.fromFLValue(doc.properties.value);

  factory Character.fromFLValue(FLValue doc) {
    return Character(
      id: doc['id'].asString,
      name: doc['name'].asString,
      description: doc['description'].asString,
      stats: {
        CharacterStat.health: [
          doc['stats.health[0]'].asInt,
          doc['stats.health[1]'].asInt
        ],
        CharacterStat.strength: [
          doc['stats.strength[0]'].asInt,
          doc['stats.strength[1]'].asInt
        ],
        CharacterStat.defence: [
          doc['stats.defence[0]'].asInt,
          doc['stats.defence[1]'].asInt
        ],
      },
      skills: doc['skills'].asList.map((e) => Skill.fromFLValue(e)).toList(),
    );
  }

  Document get document {
    final data = <String, dynamic>{
      'dt': 'character',
      'id': id,
      'name': name,
      'description': description,
      'stats': {
        CharacterStat.health.asString(): stats[CharacterStat.health],
        CharacterStat.strength.asString(): stats[CharacterStat.strength],
        CharacterStat.defence.asString(): stats[CharacterStat.defence],
        CharacterStat.speed.asString(): stats[CharacterStat.speed],
        CharacterStat.luck.asString(): stats[CharacterStat.luck],
      },
      'skills': skills?.map((e) => e.document.jsonProperties)?.toList() ?? '',
    };

    data.removeEmptyValues();
    return Document(id, data: data);
  }
Rudiksz commented 3 years ago

to modify single properties in-place you can use the fleece API

By this I mean that you can do:

Document doc = db.getMutableDocument( '1');
doc.properties['name] = 'another' ;
db.saveDocument(doc);

But the document is still saved as a whole, but without the extra parsing. This is stupidly fast, but the Fleece API needs more testing.

Rudiksz commented 3 years ago

Take a look at the Flutter app in the example folder to see what you can do with the Fleece API. https://www.youtube.com/watch?v=TLsQw7ZW9rI

richard457 commented 3 years ago

Thank you a lot, Let me deep test it out.