mongo-dart / mongo_dart

Mongo_dart: MongoDB driver for Dart programming language
https://pub.dev/packages/mongo_dart
MIT License
446 stars 98 forks source link

Feature Request: Introduce MongoClient which enables synchronous db access #368

Closed leeflix closed 3 months ago

leeflix commented 6 months ago

I was really happy to see that Dart also has a solid client for MongoDb like Python and JS. But sadly it does not provide a way to access databases synchronously like Python and JS do. Can you please provide a way to do this.

In JS you can do this for example:


const mongo = new MongoClient("mongodb://test.de:27017")
await mongo.connect()
const db = mongo.db("testDb") // this is sync
leeflix commented 6 months ago

I just implemented the following code. It kinda solves all my current problems but I am not sure if I oversee something that could go wrong in the future:


import 'package:mongo_dart/mongo_dart.dart';

class MongoClient {
  final String _connectionUri;
  Map<String, Db> _dbNameToDb = {};

  MongoClient(this._connectionUri);

  Db db(String dbName) {
    Db? db = _dbNameToDb[dbName];
    if (db != null) return db;
    db = Db(mongo.Db(_createConnectionString(dbName)));
    _dbNameToDb[dbName] = db;
    return db;
  }

  String _createConnectionString(String dbName) => "${_connectionUri}/${dbName}?authSource=admin";
}

class Db {
  mongo.Db delegate;
  bool opened = false;

  Db(this.delegate);

  DbCollection collection(String collectionName) => DbCollection(this, delegate.collection(collectionName));
}

class DbCollection {
  Db db;
  mongo.DbCollection delegate;

  DbCollection(this.db, this.delegate);

  Future<List<Map<String, dynamic>>> find([selector]) async {
    await ensureConnected();
    return delegate.find(selector).toList();
  }

  Future<Map<String, dynamic>?> findOne([selector]) async {
    await ensureConnected();
    return delegate.findOne(selector);
  }

  Future<WriteResult> replaceOne(selector, Map<String, dynamic> update, {bool? upsert, WriteConcern? writeConcern, CollationOptions? collation, String? hint, Map<String, Object>? hintDocument}) async {
    await ensureConnected();
    return delegate.replaceOne(selector, update, upsert: upsert, writeConcern: writeConcern, collation: collation, hint: hint, hintDocument: hintDocument);
  }

  Future<WriteResult> insertOne(Map<String, dynamic> document, {WriteConcern? writeConcern, bool? bypassDocumentValidation}) async {
    await ensureConnected();
    return delegate.insertOne(document, writeConcern: writeConcern, bypassDocumentValidation: bypassDocumentValidation);
  }

  Future<Map<String, dynamic>?> findAndModify({query, sort, bool? remove, update, bool? returnNew, fields, bool? upsert}) async {
    await ensureConnected();
    return delegate.findAndModify(query: query, sort: sort, remove: remove, update: update, returnNew: returnNew, fields: fields, upsert: upsert);
  }

  Future<WriteResult> deleteOne(selector, {WriteConcern? writeConcern, CollationOptions? collation, String? hint, Map<String, Object>? hintDocument}) async {
    await ensureConnected();
    return delegate.deleteOne(selector, writeConcern: writeConcern, collation: collation, hint: hint, hintDocument: hintDocument);
  }

  Future<int> count([selector]) async {
    await ensureConnected();
    return delegate.count(selector);
  }

  Future<List<Map<String, dynamic>>> aggregateToStream(List<Map<String, Object>> pipeline, {Map<String, Object> cursorOptions = const <String, Object>{}, bool allowDiskUse = false}) async {
    await ensureConnected();
    return delegate.aggregateToStream(pipeline, cursorOptions: cursorOptions, allowDiskUse: allowDiskUse).toList();
  }

  Future<WriteResult> updateOne(selector, update, {bool? upsert, WriteConcern? writeConcern, CollationOptions? collation, List<dynamic>? arrayFilters, String? hint, Map<String, Object>? hintDocument}) async {
    await ensureConnected();
    return delegate.updateOne(selector, update, upsert: upsert, writeConcern: writeConcern, collation: collation, arrayFilters: arrayFilters, hint: hint, hintDocument: hintDocument);
  }

  Future<void> ensureConnected() async {
    if (db.delegate.isConnected) return;
    await db.delegate.close();
    await db.delegate.open();
  }
}
giorgiofran commented 6 months ago

I'm working on a version of the driver with a mongo client, but it is still in an early stage. Your snippet is interesting, but I would not insert it in the package, eventually I would insert in the documentation as an example of how you can deal with the driver.

giorgiofran commented 4 months ago

If you want I have published a development version of a new driver mongo_db_driver that has support for transactions. If you have time to test it would be a great help!

giorgiofran commented 3 months ago

I close the issue.

JannikWinter commented 3 months ago

If you want I have published a development version of a new driver mongo_db_driver that has support for transactions. If you have time to test it would be a great help!

Where can I find this?

giorgiofran commented 3 months ago

on pub. You can add a dependency to mongo_db_driver instead of mongo_dart.