Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

migrating_to_5.md 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. ### Version Requirements
  2. Mongoose now requires node.js >= 4.0.0 and MongoDB >= 3.0.0. [MongoDB 2.6](https://www.mongodb.com/blog/post/mongodb-2-6-end-of-life) and [Node.js < 4](https://github.com/nodejs/Release) where both EOL-ed in 2016.
  3. ### Query Middleware
  4. Query middleware is now compiled when you call `mongoose.model()` or `db.model()`. If you add query middleware after calling `mongoose.model()`, that middleware will **not** get called.
  5. ```javascript
  6. const schema = new Schema({ name: String });
  7. const MyModel = mongoose.model('Test', schema);
  8. schema.pre('find', () => { console.log('find!'); });
  9. MyModel.find().exec(function() {
  10. // In mongoose 4.x, the above `.find()` will print "find!"
  11. // In mongoose 5.x, "find!" will **not** be printed.
  12. // Call `pre('find')` **before** calling `mongoose.model()` to make the middleware apply.
  13. });
  14. ```
  15. ### Promises and Callbacks for `mongoose.connect()`
  16. `mongoose.connect()` and `mongoose.disconnect()` now return a promise if no callback specified, or `null` otherwise. It does **not** return the mongoose singleton.
  17. ```javascript
  18. // Worked in mongoose 4. Does **not** work in mongoose 5, `mongoose.connect()`
  19. // now returns a promise consistently. This is to avoid the horrible things
  20. // we've done to allow mongoose to be a thenable that resolves to itself.
  21. mongoose.connect('mongodb://localhost:27017/test').model('Test', new Schema({}));
  22. // Do this instead
  23. mongoose.connect('mongodb://localhost:27017/test');
  24. mongoose.model('Test', new Schema({}));
  25. ```
  26. ### Connection Logic and `useMongoClient`
  27. The [`useMongoClient` option](http://mongoosejs.com/docs/4.x/docs/connections.html#use-mongo-client) was
  28. removed in Mongoose 5, it is now always `true`. As a consequence, Mongoose 5
  29. no longer supports several function signatures for `mongoose.connect()` that
  30. worked in Mongoose 4.x if the `useMongoClient` option was off. Below are some
  31. examples of `mongoose.connect()` calls that do **not** work in Mongoose 5.x.
  32. * `mongoose.connect('localhost', 27017);`
  33. * `mongoose.connect('localhost', 'mydb', 27017);`
  34. * `mongoose.connect('mongodb://host1:27017,mongodb://host2:27017');`
  35. In Mongoose 5.x, the first parameter to `mongoose.connect()` and `mongoose.createConnection()`, if specified, **must** be a [MongoDB connection string](https://docs.mongodb.com/manual/reference/connection-string/). The
  36. connection string and options are then passed down to [the MongoDB Node.js driver's `MongoClient.connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#.connect). Mongoose does not modify the connection string, although `mongoose.connect()` and `mongoose.createConnection()` support a [few additional options in addition to the ones the MongoDB driver supports](http://mongoosejs.com/docs/connections.html#options).
  37. ### Setter Order
  38. Setters run in reverse order in 4.x:
  39. ```javascript
  40. const schema = new Schema({ name: String });
  41. schema.path('name').
  42. get(() => console.log('This will print 2nd')).
  43. get(() => console.log('This will print first'));
  44. ```
  45. In 5.x, setters run in the order they're declared.
  46. ```javascript
  47. const schema = new Schema({ name: String });
  48. schema.path('name').
  49. get(() => console.log('This will print first')).
  50. get(() => console.log('This will print 2nd'));
  51. ```
  52. ### Checking if a path is populated
  53. Mongoose 5.1.0 introduced an `_id` getter to ObjectIds that lets you get an ObjectId regardless of whether a path
  54. is populated.
  55. ```javascript
  56. const blogPostSchema = new Schema({
  57. title: String,
  58. author: {
  59. type: mongoose.Schema.Types.ObjectId,
  60. ref: 'Author'
  61. }
  62. });
  63. const BlogPost = mongoose.model('BlogPost', blogPostSchema);
  64. await BlogPost.create({ title: 'test', author: author._id });
  65. const blogPost = await BlogPost.findOne();
  66. console.log(blogPost.author); // '5b207f84e8061d1d2711b421'
  67. // New in Mongoose 5.1.0: this will print '5b207f84e8061d1d2711b421' as well
  68. console.log(blogPost.author._id);
  69. await blogPost.populate('author');
  70. console.log(blogPost.author._id); '5b207f84e8061d1d2711b421'
  71. ```
  72. As a consequence, checking whether `blogPost.author._id` is [no longer viable as a way to check whether `author` is populated](https://github.com/Automattic/mongoose/issues/6415#issuecomment-388579185). Use `blogPost.populated('author') != null` or `blogPost.author instanceof mongoose.Types.ObjectId` to check whether `author` is populated instead.
  73. Note that you can call `mongoose.set('objectIdGetter', false)` to change this behavior.
  74. ### Return Values for `remove()` and `deleteX()`
  75. `deleteOne()`, `deleteMany()`, and `remove()` now resolve to the result object
  76. rather than the full [driver `WriteOpResult` object](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~writeOpCallback).
  77. ```javascript
  78. // In 4.x, this is how you got the number of documents deleted
  79. MyModel.deleteMany().then(res => console.log(res.result.n));
  80. // In 5.x this is how you get the number of documents deleted
  81. MyModel.deleteMany().then(res => res.n);
  82. ```
  83. ### Aggregation Cursors
  84. The `useMongooseAggCursor` option from 4.x is now always on. This is the new syntax for aggregation cursors in mongoose 5:
  85. ```javascript
  86. // When you call `.cursor()`, `.exec()` will now return a mongoose aggregation
  87. // cursor.
  88. const cursor = MyModel.aggregate([{ $match: { name: 'Val' } }]).cursor().exec();
  89. // No need to `await` on the cursor or wait for a promise to resolve
  90. cursor.eachAsync(doc => console.log(doc));
  91. // Can also pass options to `cursor()`
  92. const cursorWithOptions = MyModel.
  93. aggregate([{ $match: { name: 'Val' } }]).
  94. cursor({ batchSize: 10 }).
  95. exec();
  96. ```
  97. ### geoNear
  98. `Model.geoNear()` has been removed because the [MongoDB driver no longer supports it](https://github.com/mongodb/node-mongodb-native/blob/master/CHANGES_3.0.0.md#geonear-command-helper)
  99. ### Required URI encoding of connection strings
  100. Due to changes in the MongoDB driver, connection strings must be URI encoded.
  101. If they are not, connections may fail with an illegal character message.
  102. #### Passwords which contain certain characters
  103. See a [full list of affected characters](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding).
  104. If your app is used by a lot of different connection strings, it's possible
  105. that your test cases will pass, but production passwords will fail. Encode all your connection
  106. strings to be safe.
  107. If you want to continue to use unencoded connection strings, the easiest fix is to use
  108. the `mongodb-uri` module to parse the connection strings, and then produce the properly encoded
  109. versions. You can use a function like this:
  110. ```javascript
  111. const uriFormat = require('mongodb-uri')
  112. function encodeMongoURI (urlString) {
  113. if (urlString) {
  114. let parsed = uriFormat.parse(urlString)
  115. urlString = uriFormat.format(parsed);
  116. }
  117. return urlString;
  118. }
  119. }
  120. // Your un-encoded string.
  121. const mongodbConnectString = "mongodb://...";
  122. mongoose.connect(encodeMongoURI(mongodbConnectString))
  123. ```
  124. The function above is safe to use whether the existing string is already encoded or not.
  125. #### Domain sockets
  126. Domain sockets must be URI encoded. For example:
  127. ```javascript
  128. // Works in mongoose 4. Does **not** work in mongoose 5 because of more
  129. // stringent URI parsing.
  130. const host = '/tmp/mongodb-27017.sock';
  131. mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`);
  132. // Do this instead
  133. const host = encodeURIComponent('/tmp/mongodb-27017.sock');
  134. mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`);
  135. ```
  136. ### `toObject()` Options
  137. The `options` parameter to `toObject()` and `toJSON()` merge defaults rather than overwriting them.
  138. ```javascript
  139. // Note the `toObject` option below
  140. const schema = new Schema({ name: String }, { toObject: { virtuals: true } });
  141. schema.virtual('answer').get(() => 42);
  142. const MyModel = db.model('MyModel', schema);
  143. const doc = new MyModel({ name: 'test' });
  144. // In mongoose 4.x this prints "undefined", because `{ minimize: false }`
  145. // overwrites the entire schema-defined options object.
  146. // In mongoose 5.x this prints "42", because `{ minimize: false }` gets
  147. // merged with the schema-defined options.
  148. console.log(doc.toJSON({ minimize: false }).answer);
  149. ```
  150. ### Aggregate Parameters
  151. `aggregate()` no longer accepts a spread, you **must** pass your aggregation pipeline as an array. The below code worked in 4.x:
  152. ```javascript
  153. MyModel.aggregate({ $match: { isDeleted: false } }, { $skip: 10 }).exec(cb);
  154. ```
  155. The above code does **not** work in 5.x, you **must** wrap the `$match` and `$skip` stages in an array.
  156. ```javascript
  157. MyModel.aggregate([{ $match: { isDeleted: false } }, { $skip: 10 }]).exec(cb);
  158. ```
  159. ### Boolean Casting
  160. By default, mongoose 4 would coerce any value to a boolean without error.
  161. ```javascript
  162. // Fine in mongoose 4, would save a doc with `boolField = true`
  163. const MyModel = mongoose.model('Test', new Schema({
  164. boolField: Boolean
  165. }));
  166. MyModel.create({ boolField: 'not a boolean' });
  167. ```
  168. Mongoose 5 only casts the following values to `true`:
  169. * `true`
  170. * `'true'`
  171. * `1`
  172. * `'1'`
  173. * `'yes'`
  174. And the following values to `false`:
  175. * `false`
  176. * `'false'`
  177. * `0`
  178. * `'0'`
  179. * `'no'`
  180. All other values will cause a `CastError`
  181. ### Query Casting
  182. Casting for `update()`, `updateOne()`, `updateMany()`, `replaceOne()`,
  183. `remove()`, `deleteOne()`, and `deleteMany()` doesn't happen until `exec()`.
  184. This makes it easier for hooks and custom query helpers to modify data, because
  185. mongoose won't restructure the data you passed in until after your hooks and
  186. query helpers have ran. It also makes it possible to set the `overwrite` option
  187. _after_ passing in an update.
  188. ```javascript
  189. // In mongoose 4.x, this becomes `{ $set: { name: 'Baz' } }` despite the `overwrite`
  190. // In mongoose 5.x, this overwrite is respected and the first document with
  191. // `name = 'Bar'` will be replaced with `{ name: 'Baz' }`
  192. User.where({ name: 'Bar' }).update({ name: 'Baz' }).setOptions({ overwrite: true });
  193. ```
  194. ### Post Save Hooks Get Flow Control
  195. Post hooks now get flow control, which means async post save hooks and child document post save hooks execute **before** your `save()` callback.
  196. ```javsscript
  197. const ChildModelSchema = new mongoose.Schema({
  198. text: {
  199. type: String
  200. }
  201. });
  202. ChildModelSchema.post('save', function(doc) {
  203. // In mongoose 5.x this will print **before** the `console.log()`
  204. // in the `save()` callback. In mongoose 4.x this was reversed.
  205. console.log('Child post save');
  206. });
  207. const ParentModelSchema = new mongoose.Schema({
  208. children: [ChildModelSchema]
  209. });
  210. const Model = mongoose.model('Parent', ParentModelSchema);
  211. const m = new Model({ children: [{ text: 'test' }] });
  212. m.save(function() {
  213. // In mongoose 5.xm this prints **after** the "Child post save" message.
  214. console.log('Save callback');
  215. });
  216. ```
  217. ### The `$pushAll` Operator
  218. `$pushAll` is no longer supported and no longer used internally for `save()`, since it has been [deprecated since MongoDB 2.4](https://docs.mongodb.com/manual/reference/operator/update/pushAll/). Use `$push` with `$each` instead.
  219. ### Always Use Forward Key Order
  220. The `retainKeyOrder` option was removed, mongoose will now always retain the same key position when cloning objects. If you have queries or indexes that rely on reverse key order, you will have to change them.
  221. ### Run setters on queries
  222. Setters now run on queries by default, and the old `runSettersOnQuery` option
  223. has been removed.
  224. ```javascript
  225. const schema = new Schema({
  226. email: { type: String, lowercase: true }
  227. });
  228. const Model = mongoose.model('Test', schema);
  229. Model.find({ email: 'FOO@BAR.BAZ' }); // Converted to `find({ email: 'foo@bar.baz' })`
  230. ```
  231. ### Pre-compiled Browser Bundle
  232. We no longer have a pre-compiled version of mongoose for the browser. If you want to use mongoose schemas in the browser, you need to build your own bundle with browserify/webpack.
  233. ### Save Errors
  234. The `saveErrorIfNotFound` option was removed, mongoose will now always error out from `save()` if the underlying document was not found
  235. ### Init hook signatures
  236. `init` hooks are now fully synchronous and do not receive `next()` as a parameter.
  237. `Document.prototype.init()` no longer takes a callback as a parameter. It
  238. was always synchronous, just had a callback for legacy reasons.
  239. ### `numAffected` and `save()`
  240. `doc.save()` no longer passes `numAffected` as a 3rd param to its callback.
  241. ### `remove()` and debouncing
  242. `doc.remove()` no longer debounces
  243. ### `getPromiseConstructor()`
  244. `getPromiseConstructor()` is gone, just use `mongoose.Promise`.
  245. ### Passing Parameters from Pre Hooks
  246. You cannot pass parameters to the next pre middleware in the chain using `next()` in mongoose 5.x. In mongoose 4, `next('Test')` in pre middleware would call the
  247. next middleware with 'Test' as a parameter. Mongoose 5.x has removed support for this.
  248. ### `required` validator for arrays
  249. In mongoose 5 the `required` validator only verifies if the value is an array. That is, it will **not** fail for _empty_ arrays as it would in mongoose 4.
  250. ### debug output defaults to stdout instead of stderr
  251. In mongoose 5 the default debug function uses `console.info()` to display messages instead of `console.error()`.
  252. ### Overwriting filter properties
  253. In Mongoose 4.x, overwriting a filter property that's a primitive with one that is an object would silently fail. For example, the below code would ignore the `where()` and be equivalent to `Sport.find({ name: 'baseball' })`
  254. ```javascript
  255. Sport.find({ name: 'baseball' }).where({name: {$ne: 'softball'}});
  256. ```
  257. In Mongoose 5.x, the above code will correctly overwrite `'baseball'` with `{ $ne: 'softball' }`
  258. ### `bulkWrite()` results
  259. Mongoose 5.x uses version 3.x of the [MongoDB Node.js driver](http://npmjs.com/package/mongodb). MongoDB driver 3.x changed the format of
  260. the result of [`bulkWrite()` calls](http://localhost:8088/docs/api.html#model_Model.bulkWrite) so there is no longer a top-level `nInserted`, `nModified`, etc. property. The new result object structure is [described here](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#~BulkWriteOpResult).
  261. ```javascript
  262. const Model = mongoose.model('Test', new Schema({ name: String }));
  263. const res = await Model.bulkWrite([{ insertOne: { document: { name: 'test' } } }]);
  264. console.log(res);
  265. ```
  266. In Mongoose 4.x, the above will print:
  267. ```
  268. BulkWriteResult {
  269. ok: [Getter],
  270. nInserted: [Getter],
  271. nUpserted: [Getter],
  272. nMatched: [Getter],
  273. nModified: [Getter],
  274. nRemoved: [Getter],
  275. getInsertedIds: [Function],
  276. getUpsertedIds: [Function],
  277. getUpsertedIdAt: [Function],
  278. getRawResponse: [Function],
  279. hasWriteErrors: [Function],
  280. getWriteErrorCount: [Function],
  281. getWriteErrorAt: [Function],
  282. getWriteErrors: [Function],
  283. getLastOp: [Function],
  284. getWriteConcernError: [Function],
  285. toJSON: [Function],
  286. toString: [Function],
  287. isOk: [Function],
  288. insertedCount: 1,
  289. matchedCount: 0,
  290. modifiedCount: 0,
  291. deletedCount: 0,
  292. upsertedCount: 0,
  293. upsertedIds: {},
  294. insertedIds: { '0': 5be9a3101638a066702a0d38 },
  295. n: 1 }
  296. ```
  297. In Mongoose 5.x, the script will print:
  298. ```
  299. BulkWriteResult {
  300. result:
  301. { ok: 1,
  302. writeErrors: [],
  303. writeConcernErrors: [],
  304. insertedIds: [ [Object] ],
  305. nInserted: 1,
  306. nUpserted: 0,
  307. nMatched: 0,
  308. nModified: 0,
  309. nRemoved: 0,
  310. upserted: [],
  311. lastOp: { ts: [Object], t: 1 } },
  312. insertedCount: 1,
  313. matchedCount: 0,
  314. modifiedCount: 0,
  315. deletedCount: 0,
  316. upsertedCount: 0,
  317. upsertedIds: {},
  318. insertedIds: { '0': 5be9a1c87decfc6443dd9f18 },
  319. n: 1 }
  320. ```