setDefaultsOnInsert.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. var modifiedPaths = require('./common').modifiedPaths;
  3. /**
  4. * Applies defaults to update and findOneAndUpdate operations.
  5. *
  6. * @param {Query} query
  7. * @param {Schema} schema
  8. * @param {Object} castedDoc
  9. * @param {Object} options
  10. * @method setDefaultsOnInsert
  11. * @api private
  12. */
  13. module.exports = function(query, schema, castedDoc, options) {
  14. var keys = Object.keys(castedDoc || {});
  15. var updatedKeys = {};
  16. var updatedValues = {};
  17. var numKeys = keys.length;
  18. var hasDollarUpdate = false;
  19. var modified = {};
  20. if (options && options.upsert) {
  21. for (var i = 0; i < numKeys; ++i) {
  22. if (keys[i].charAt(0) === '$') {
  23. modifiedPaths(castedDoc[keys[i]], '', modified);
  24. hasDollarUpdate = true;
  25. }
  26. }
  27. if (!hasDollarUpdate) {
  28. modifiedPaths(castedDoc, '', modified);
  29. }
  30. var paths = Object.keys(query._conditions);
  31. var numPaths = keys.length;
  32. for (i = 0; i < numPaths; ++i) {
  33. var path = paths[i];
  34. var condition = query._conditions[path];
  35. if (condition && typeof condition === 'object') {
  36. var conditionKeys = Object.keys(condition);
  37. var numConditionKeys = conditionKeys.length;
  38. var hasDollarKey = false;
  39. for (var j = 0; j < numConditionKeys; ++j) {
  40. if (conditionKeys[j].charAt(0) === '$') {
  41. hasDollarKey = true;
  42. break;
  43. }
  44. }
  45. if (hasDollarKey) {
  46. continue;
  47. }
  48. }
  49. updatedKeys[path] = true;
  50. modified[path] = true;
  51. }
  52. if (options.setDefaultsOnInsert) {
  53. schema.eachPath(function(path, schemaType) {
  54. if (path === '_id') {
  55. // Ignore _id for now because it causes bugs in 2.4
  56. return;
  57. }
  58. if (schemaType.$isSingleNested) {
  59. // Only handle nested schemas 1-level deep to avoid infinite
  60. // recursion re: https://github.com/mongodb-js/mongoose-autopopulate/issues/11
  61. schemaType.schema.eachPath(function(_path, _schemaType) {
  62. if (path === '_id') {
  63. // Ignore _id for now because it causes bugs in 2.4
  64. return;
  65. }
  66. var def = _schemaType.getDefault(null, true);
  67. if (!modified[path + '.' + _path] && typeof def !== 'undefined') {
  68. castedDoc = castedDoc || {};
  69. castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
  70. castedDoc.$setOnInsert[path + '.' + _path] = def;
  71. updatedValues[path + '.' + _path] = def;
  72. }
  73. });
  74. } else {
  75. var def = schemaType.getDefault(null, true);
  76. if (!modified[path] && typeof def !== 'undefined') {
  77. castedDoc = castedDoc || {};
  78. castedDoc.$setOnInsert = castedDoc.$setOnInsert || {};
  79. castedDoc.$setOnInsert[path] = def;
  80. updatedValues[path] = def;
  81. }
  82. }
  83. });
  84. }
  85. }
  86. return castedDoc;
  87. };