0
# Document Manipulation
1
2
Document instance methods for saving, validation, field access, and lifecycle management with change tracking and middleware support.
3
4
## Capabilities
5
6
### Document Lifecycle
7
8
Methods for saving, validating, and managing document lifecycle with automatic change detection.
9
10
```javascript { .api }
11
interface Document {
12
/**
13
* Save document to database
14
* @param options - Save options
15
* @returns Promise resolving to saved document
16
*/
17
save(options?: SaveOptions): Promise<this>;
18
19
/**
20
* Validate document against schema
21
* @param pathsToValidate - Specific paths to validate
22
* @param options - Validation options
23
* @returns Promise resolving when validation completes
24
*/
25
validate(pathsToValidate?: string[], options?: ValidateOptions): Promise<void>;
26
27
/**
28
* Synchronously validate document
29
* @param pathsToValidate - Specific paths to validate
30
* @returns ValidationError if invalid, null if valid
31
*/
32
validateSync(pathsToValidate?: string[]): ValidationError | null;
33
34
/**
35
* Delete this document
36
* @param options - Delete options
37
* @returns Promise resolving to deleted document
38
*/
39
deleteOne(options?: DeleteOptions): Promise<this>;
40
41
/**
42
* Remove document (deprecated, use deleteOne)
43
* @param options - Remove options
44
* @returns Promise resolving to removed document
45
*/
46
remove(options?: RemoveOptions): Promise<this>;
47
}
48
49
interface SaveOptions {
50
/** Skip validation */
51
validateBeforeSave?: boolean;
52
53
/** Validate only modified paths */
54
validateModifiedOnly?: boolean;
55
56
/** Specific paths to validate */
57
pathsToValidate?: string[];
58
59
/** Database session */
60
session?: ClientSession;
61
62
/** Suppress '_id' on save */
63
suppressReservedKeysWarning?: boolean;
64
}
65
```
66
67
**Usage Examples:**
68
69
```javascript
70
const User = mongoose.model('User', userSchema);
71
72
// Create and save document
73
const user = new User({
74
name: 'John Doe',
75
email: 'john@example.com',
76
age: 30
77
});
78
79
await user.save();
80
81
// Validate before operations
82
try {
83
await user.validate();
84
console.log('Document is valid');
85
} catch (error) {
86
console.log('Validation errors:', error.errors);
87
}
88
89
// Save with options
90
await user.save({
91
validateBeforeSave: false,
92
pathsToValidate: ['name', 'email']
93
});
94
95
// Delete document
96
await user.deleteOne();
97
```
98
99
### Field Access and Modification
100
101
Methods for getting, setting, and tracking changes to document fields.
102
103
```javascript { .api }
104
interface Document {
105
/**
106
* Get field value with path notation
107
* @param path - Field path (dot notation supported)
108
* @param type - Cast to specific type
109
* @returns Field value
110
*/
111
get(path: string, type?: any): any;
112
113
/**
114
* Set field value with path notation
115
* @param path - Field path or object of paths/values
116
* @param val - Value to set
117
* @param type - Schema type for casting
118
* @param options - Set options
119
* @returns this document
120
*/
121
set(path: string | object, val?: any, type?: any, options?: SetOptions): this;
122
123
/**
124
* Mark field as modified for change tracking
125
* @param path - Field path to mark as modified
126
* @param val - New value (optional)
127
* @returns this document
128
*/
129
markModified(path: string, val?: any): this;
130
131
/**
132
* Unmark field as modified
133
* @param path - Field path to unmark
134
* @returns this document
135
*/
136
unmarkModified(path: string): this;
137
138
/**
139
* Check if field is modified
140
* @param path - Field path to check (optional, checks any modification if omitted)
141
* @returns true if modified
142
*/
143
isModified(path?: string): boolean;
144
145
/**
146
* Get array of modified field paths
147
* @param options - Options for getting modified paths
148
* @returns Array of modified paths
149
*/
150
modifiedPaths(options?: { includeChildren?: boolean }): string[];
151
152
/**
153
* Check if field was selected in query
154
* @param path - Field path to check
155
* @returns true if selected
156
*/
157
isSelected(path: string): boolean;
158
159
/**
160
* Check if field is initialized
161
* @param path - Field path to check
162
* @returns true if initialized
163
*/
164
isInit(path: string): boolean;
165
}
166
167
interface SetOptions {
168
/** Strict mode for this operation */
169
strict?: boolean;
170
171
/** Merge objects instead of overwriting */
172
merge?: boolean;
173
}
174
```
175
176
**Usage Examples:**
177
178
```javascript
179
const user = new User({ name: 'John', profile: { age: 30 } });
180
181
// Get field values
182
console.log(user.get('name')); // 'John'
183
console.log(user.get('profile.age')); // 30
184
185
// Set field values
186
user.set('name', 'Jane');
187
user.set('profile.age', 31);
188
189
// Set multiple fields at once
190
user.set({
191
name: 'Bob',
192
email: 'bob@example.com'
193
});
194
195
// Check modifications
196
console.log(user.isModified('name')); // true
197
console.log(user.modifiedPaths()); // ['name', 'profile.age']
198
199
// Mark additional fields as modified
200
user.markModified('customField');
201
202
// Reset modification tracking
203
user.unmarkModified('name');
204
```
205
206
### Document Properties
207
208
Key properties available on all document instances.
209
210
```javascript { .api }
211
interface Document {
212
/** Document ID as string */
213
id: string;
214
215
/** Document ObjectId */
216
_id: ObjectId;
217
218
/** True if document is new (not saved to database) */
219
isNew: boolean;
220
221
/** Document version number (if versioning enabled) */
222
__v?: number;
223
224
/** Reference to document's schema */
225
$__: DocumentInternals;
226
227
/** Document errors from validation */
228
errors?: ValidationError;
229
230
/** True if document is deleted */
231
$isDeleted: boolean;
232
}
233
```
234
235
### Document Serialization
236
237
Convert documents to plain JavaScript objects or JSON with transformation options.
238
239
```javascript { .api }
240
interface Document {
241
/**
242
* Convert document to plain JavaScript object
243
* @param options - Transformation options
244
* @returns Plain object representation
245
*/
246
toObject(options?: ToObjectOptions): any;
247
248
/**
249
* Convert document to JSON representation
250
* @param options - Transformation options
251
* @returns JSON-serializable object
252
*/
253
toJSON(options?: ToObjectOptions): any;
254
255
/**
256
* Get string representation of document
257
* @returns String representation
258
*/
259
toString(): string;
260
261
/**
262
* Inspect document (Node.js util.inspect)
263
* @returns Object for inspection
264
*/
265
inspect(): any;
266
}
267
268
interface ToObjectOptions {
269
/** Include getter functions */
270
getters?: boolean;
271
272
/** Include virtual properties */
273
virtuals?: boolean;
274
275
/** Include version key */
276
versionKey?: boolean;
277
278
/** Minimize empty objects */
279
minimize?: boolean;
280
281
/** Transform function */
282
transform?: (doc: any, ret: any, options: any) => any;
283
284
/** Flatten Maps to objects */
285
flattenMaps?: boolean;
286
287
/** Depopulate populated paths */
288
depopulate?: boolean;
289
290
/** Use aliases instead of actual field names */
291
useProjection?: boolean;
292
}
293
```
294
295
**Usage Examples:**
296
297
```javascript
298
const user = await User.findById(userId).populate('friends');
299
300
// Convert to plain object
301
const userObj = user.toObject();
302
303
// Convert with options
304
const cleanUser = user.toObject({
305
virtuals: true,
306
getters: true,
307
minimize: false,
308
transform: function(doc, ret) {
309
delete ret._id;
310
delete ret.__v;
311
return ret;
312
}
313
});
314
315
// Convert to JSON (used by JSON.stringify)
316
const userJson = user.toJSON();
317
318
// Custom JSON transformation
319
userSchema.set('toJSON', {
320
virtuals: true,
321
transform: function(doc, ret) {
322
ret.id = ret._id;
323
delete ret._id;
324
delete ret.__v;
325
return ret;
326
}
327
});
328
```
329
330
### Population
331
332
Populate referenced documents and manage populated data.
333
334
```javascript { .api }
335
interface Document {
336
/**
337
* Populate referenced fields
338
* @param path - Path to populate or populate options
339
* @returns Promise resolving to populated document
340
*/
341
populate(path: string | PopulateOptions | PopulateOptions[]): Promise<this>;
342
343
/**
344
* Get populated document(s) for a path
345
* @param path - Path to check
346
* @returns Populated value or undefined
347
*/
348
populated(path: string): any;
349
350
/**
351
* Remove populated values and restore ObjectIds
352
* @param path - Path to depopulate (optional, depopulates all if omitted)
353
* @returns this document
354
*/
355
depopulate(path?: string): this;
356
357
/**
358
* Explicitly populate virtual fields
359
* @param path - Virtual path to populate
360
* @returns Promise resolving to populated document
361
*/
362
execPopulate(): Promise<this>;
363
}
364
365
interface PopulateOptions {
366
/** Path to populate */
367
path: string;
368
369
/** Fields to select from populated documents */
370
select?: string | object;
371
372
/** Model to populate from */
373
model?: string | Model<any>;
374
375
/** Additional query conditions */
376
match?: any;
377
378
/** Sort populated documents */
379
sort?: any;
380
381
/** Limit populated documents */
382
limit?: number;
383
384
/** Skip populated documents */
385
skip?: number;
386
387
/** Populate nested fields */
388
populate?: PopulateOptions | PopulateOptions[];
389
390
/** Preserve null and undefined values */
391
strictPopulate?: boolean;
392
}
393
```
394
395
**Usage Examples:**
396
397
```javascript
398
// Schema with references
399
const postSchema = new Schema({
400
title: String,
401
author: { type: Schema.Types.ObjectId, ref: 'User' },
402
comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }]
403
});
404
405
const post = await Post.findById(postId);
406
407
// Basic population
408
await post.populate('author');
409
console.log(post.author.name); // Populated user name
410
411
// Population with field selection
412
await post.populate('author', 'name email');
413
414
// Population with conditions
415
await post.populate({
416
path: 'comments',
417
match: { approved: true },
418
select: 'text createdAt',
419
sort: { createdAt: -1 }
420
});
421
422
// Multiple populations
423
await post.populate([
424
{ path: 'author', select: 'name' },
425
{ path: 'comments', populate: { path: 'author', select: 'name' } }
426
]);
427
428
// Check if populated
429
if (post.populated('author')) {
430
console.log('Author is populated');
431
}
432
433
// Depopulate
434
post.depopulate('author');
435
console.log(post.author); // ObjectId again
436
```
437
438
### Document Comparison and Manipulation
439
440
Methods for comparing documents and performing advanced manipulations.
441
442
```javascript { .api }
443
interface Document {
444
/**
445
* Check equality with another document
446
* @param doc - Document to compare with
447
* @returns true if equal
448
*/
449
equals(doc: Document): boolean;
450
451
/**
452
* Increment numeric field values
453
* @returns this document
454
*/
455
increment(): this;
456
457
/**
458
* Overwrite document with new data
459
* @param obj - New document data
460
* @returns this document
461
*/
462
overwrite(obj: any): this;
463
464
/**
465
* Update document in database
466
* @param update - Update operations
467
* @param options - Update options
468
* @returns Query instance
469
*/
470
updateOne(update: UpdateQuery<this>, options?: UpdateOptions): Query<UpdateResult, this>;
471
472
/**
473
* Replace document in database
474
* @param replacement - Replacement data
475
* @param options - Replace options
476
* @returns Query instance
477
*/
478
replaceOne(replacement: any, options?: ReplaceOptions): Query<UpdateResult, this>;
479
}
480
```
481
482
**Usage Examples:**
483
484
```javascript
485
const user1 = await User.findById(id1);
486
const user2 = await User.findById(id2);
487
488
// Compare documents
489
if (user1.equals(user2)) {
490
console.log('Same document');
491
}
492
493
// Increment version
494
user1.increment();
495
await user1.save();
496
497
// Overwrite with new data
498
user1.overwrite({
499
name: 'New Name',
500
email: 'new@example.com'
501
});
502
503
// Update in database
504
await user1.updateOne({ $set: { lastLogin: new Date() } });
505
506
// Replace in database
507
await user1.replaceOne({
508
name: 'Replacement Name',
509
email: 'replacement@example.com'
510
});
511
```
512
513
## Types
514
515
```javascript { .api }
516
interface ValidateOptions {
517
/** Paths to skip during validation */
518
pathsToSkip?: string[];
519
520
/** Run validators on all paths */
521
validateModifiedOnly?: boolean;
522
}
523
524
interface ValidationError extends Error {
525
/** Validation errors by path */
526
errors: { [path: string]: ValidatorError };
527
528
/** Error type identifier */
529
kind: 'ValidationError';
530
}
531
532
interface ValidatorError extends Error {
533
/** Path that failed validation */
534
path: string;
535
536
/** Value that failed validation */
537
value: any;
538
539
/** Validator type */
540
kind: string;
541
542
/** Schema type that failed */
543
schemaType: SchemaType;
544
}
545
546
interface DocumentInternals {
547
/** Document state tracking */
548
selected: any;
549
modified: Set<string>;
550
errors: ValidationError;
551
validationError: ValidationError;
552
adhocPaths: any;
553
removing: boolean;
554
inserting: boolean;
555
version: number;
556
getters: any;
557
populate: any;
558
populated: any;
559
wasPopulated: boolean;
560
scope: any;
561
activePaths: any;
562
pathsToScopes: any;
563
cachedRequired: any;
564
session: ClientSession;
565
ownerDocument: Document;
566
fullPath: string;
567
emitter: EventEmitter;
568
'$options': any;
569
}
570
```