assignRawDocsToIdStructure.js 3.0 KB

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