mongo_document_annotation 1.0.1
mongo_document_annotation: ^1.0.1 copied to clipboard
› Generate MongoDB CRUD code from Dart classes annotated with @MongoDocument.
Table of Contents #
Overview #
mongo_document bridges Dart freezed
models and MongoDB via mongo_dart
, generating zero‑boilerplate, type‑safe CRUD and query builders that respect your Dart-native naming conventions (e.g. camelCase) while serializing to your DB schema (e.g. snake_case).
⚠️ Work in Progress: Experimental features may change. Your feedback and contributions are welcome.
Features #
-
Document References & Propagation — support for referencing other
@MongoDocument
models (e.g.User? author
inPost
), storing anObjectId
behind the scenes and automatically propagating.save()
calls to nested documents -
Zero‑Boilerplate CRUD — instance methods:
.save()
,.delete()
, static helpers:.insertMany()
-
Zero‑Boilerplate CRUD — instance methods:
.save()
,.delete()
, static helpers:.insertMany()
-
Type‑Safe Query DSL —
.findOne()
,.findMany()
,.updateOne()
,.deleteMany()
,.count()
-
Nested Joins — automatic
$lookup
+$unwind
for referenced@MongoDocument
relations -
Array & Map Support —
QList<T>
(.contains(), .elemMatch()),QMap<V>
(sub-key queries) -
Field Renaming — honors
@JsonSerializable(fieldRename: …)
settings without manual mapping -
Timestamps & IDs — auto-manages
_id
,created_at
,updated_at
Getting Started #
Prerequisites #
-
Dart SDK ≥ 2.18
-
A running MongoDB instance (local or remote)
-
MongoDB server version ≥ 3.6 (this library does not support older MongoDB releases)
Installation #
Add to your pubspec.yaml
:
dependencies:
json_annotation: ^4.9.0
mongo_document: ^0.0.1
dev_dependencies:
build_runner: ^2.4.14
freezed: ">=2.5.8 <4.0.0"
json_serializable: ^6.9.3
mongo_document_generator: ^0.0.1
Then:
dart pub get
Initialization #
In your application entrypoint (e.g. main()
), configure the MongoDB connection once:
import 'package:mongo_document/mongo_connection.dart';
Future<void> main() async {
await MongoConnection.init('mongodb://localhost:27017/mydb');
// Now you can use generated .save(), .findOne(), etc.
}
Usage #
Defining Models #
⚠️ Requirement: Every @MongoDocument
class must include an ObjectId
field in its primary constructor annotated with @JsonKey(name: '_id')
. This ensures a valid MongoDB _id
is always present.
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:mongo_document/mongo_document.dart';
part 'post.freezed.dart';
part 'post.g.dart';
part 'post.mongo_document.dart';
@freezed
@MongoDocument(collection: 'posts')
abstract class Post with _$Post {
@JsonSerializable(fieldRename: FieldRename.snake, explicitToJson: true)
const factory Post({
@ObjectIdConverter() @JsonKey(name: '_id') ObjectId? id,
User? author,
String? body,
@Default(<String>[]) List<String> tags,
@DateTimeConverter() DateTime? createdAt,
@DateTimeConverter() DateTime? updatedAt,
}) = _Post;
factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
}
Generating Code #
Run build_runner to generate .mongo_document.dart
helpers:
dart run build_runner build --delete-conflicting-outputs
This creates:
- Model instance methods:
.save()
,.delete()
- Static APIs:
Posts.findOne()
,Posts.findMany()
, etc. - Query builder
QPost
with typed fields, lists, maps.
CRUD Examples #
// Create & save
final newPost = Post(body: 'Hello world', tags: ['intro']);
await newPost.save();
// Read
final post = await Posts.findOne((p) => p.body.eq('Hello world'));
// Update
post = post?.copyWith(body: 'Updated');
await post?.save();
// Delete
await post?.delete();
Advanced Queries #
// Find posts whose tags array contain "viral"
final viralPosts = await Posts.findMany(
(p) => p.tags.contains("viral")
);
// Map key query: analytics['views'] > 100
final hot = await Posts.findMany(
(p) => p.analytics['views'].gt(100)
);
// Count documents
final total = await Posts.count((p) => p.body.ne(null));
References & Propagation #
You can reference other MongoDocument models and have nested saves propagate automatically. Behind the scenes, a reference field stores the related document's ObjectId
, and invoking .save()
on the parent will also persist changes in the referenced document.
// Load and modify a referenced User
User? author = await Users.findById(authorId);
author = author?.copyWith(firstName: 'newName');
// Load a Post, update its author reference, then save both
Post? post = await Posts.findById(postId);
post = post?.copyWith(author: author);
await post?.save(); // changes to `author` propagate to the users collection
Configuration & Conventions #
- Customize converters via
@ObjectIdConverter()
and@DateTimeConverter()
. - Collection name comes from
@MongoDocument(collection: ...)
.
Troubleshooting #
Warning: @JsonSerializable can only be used on classes
Add to your analysis_options.yaml
:
analyzer:
errors:
invalid_annotation_target: ignore
Contributing #
Contributions, issues, and feature requests are welcome! Please see CONTRIBUTING.md for details.
License #
This project is licensed under the MIT License. See LICENSE for details.