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.

112 lines
3.5 KiB

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