assignRawDocsToIdStructure.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. 'use strict';
  2. const clone = require('../../helpers/clone');
  3. const leanPopulateMap = require('./leanPopulateMap');
  4. const modelSymbol = require('../symbols').modelSymbol;
  5. const utils = require('../../utils');
  6. module.exports = assignRawDocsToIdStructure;
  7. const kHasArray = Symbol('mongoose#assignRawDocsToIdStructure#hasArray');
  8. /**
  9. * Assign `vals` returned by mongo query to the `rawIds`
  10. * structure returned from utils.getVals() honoring
  11. * query sort order if specified by user.
  12. *
  13. * This can be optimized.
  14. *
  15. * Rules:
  16. *
  17. * if the value of the path is not an array, use findOne rules, else find.
  18. * for findOne the results are assigned directly to doc path (including null results).
  19. * for find, if user specified sort order, results are assigned directly
  20. * else documents are put back in original order of array if found in results
  21. *
  22. * @param {Array} rawIds
  23. * @param {Array} resultDocs
  24. * @param {Array} resultOrder
  25. * @param {Object} options
  26. * @param {Boolean} recursed
  27. * @api private
  28. */
  29. function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, recursed) {
  30. // honor user specified sort order, unless we're populating a single
  31. // virtual underneath an array (e.g. populating `employees.mostRecentShift` where
  32. // `mostRecentShift` is a virtual with `justOne`)
  33. const newOrder = [];
  34. const sorting = options.isVirtual && options.justOne && rawIds.length > 1
  35. ? false :
  36. options.sort && rawIds.length > 1;
  37. const nullIfNotFound = options.$nullIfNotFound;
  38. let doc;
  39. let sid;
  40. let id;
  41. if (utils.isMongooseArray(rawIds)) {
  42. rawIds = rawIds.__array;
  43. }
  44. let i = 0;
  45. const len = rawIds.length;
  46. if (sorting && recursed && options[kHasArray] === undefined) {
  47. options[kHasArray] = false;
  48. for (const key in resultOrder) {
  49. if (Array.isArray(resultOrder[key])) {
  50. options[kHasArray] = true;
  51. break;
  52. }
  53. }
  54. }
  55. for (i = 0; i < len; ++i) {
  56. id = rawIds[i];
  57. if (Array.isArray(id)) {
  58. // handle [ [id0, id2], [id3] ]
  59. assignRawDocsToIdStructure(id, resultDocs, resultOrder, options, true);
  60. newOrder.push(id);
  61. continue;
  62. }
  63. if (id === null && sorting === false) {
  64. // keep nulls for findOne unless sorting, which always
  65. // removes them (backward compat)
  66. newOrder.push(id);
  67. continue;
  68. }
  69. sid = String(id);
  70. doc = resultDocs[sid];
  71. // If user wants separate copies of same doc, use this option
  72. if (options.clone && doc != null) {
  73. if (options.lean) {
  74. const _model = leanPopulateMap.get(doc);
  75. doc = clone(doc);
  76. leanPopulateMap.set(doc, _model);
  77. } else {
  78. doc = doc.constructor.hydrate(doc._doc);
  79. }
  80. }
  81. if (recursed) {
  82. if (doc) {
  83. if (sorting) {
  84. const _resultOrder = resultOrder[sid];
  85. if (options[kHasArray]) {
  86. // If result arrays, rely on the MongoDB server response for ordering
  87. newOrder.push(doc);
  88. } else {
  89. newOrder[_resultOrder] = doc;
  90. }
  91. } else {
  92. newOrder.push(doc);
  93. }
  94. } else if (id?.[modelSymbol] != null) {
  95. newOrder.push(id);
  96. } else {
  97. newOrder.push(options.retainNullValues || nullIfNotFound ? null : id);
  98. }
  99. } else {
  100. // apply findOne behavior - if document in results, assign, else assign null
  101. newOrder[i] = doc || null;
  102. }
  103. }
  104. rawIds.length = 0;
  105. if (newOrder.length) {
  106. // reassign the documents based on corrected order
  107. // forEach skips over sparse entries in arrays so we
  108. // can safely use this to our advantage dealing with sorted
  109. // result sets too.
  110. newOrder.forEach(function(doc, i) {
  111. rawIds[i] = doc;
  112. });
  113. }
  114. }