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.

assignVals.js 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. 'use strict';
  2. const assignRawDocsToIdStructure = require('./assignRawDocsToIdStructure');
  3. const get = require('../get');
  4. const getVirtual = require('./getVirtual');
  5. const leanPopulateMap = require('./leanPopulateMap');
  6. const mpath = require('mpath');
  7. const sift = require('sift').default;
  8. const utils = require('../../utils');
  9. module.exports = function assignVals(o) {
  10. // Options that aren't explicitly listed in `populateOptions`
  11. const userOptions = get(o, 'allOptions.options.options');
  12. // `o.options` contains options explicitly listed in `populateOptions`, like
  13. // `match` and `limit`.
  14. const populateOptions = Object.assign({}, o.options, userOptions, {
  15. justOne: o.justOne
  16. });
  17. const originalIds = [].concat(o.rawIds);
  18. // replace the original ids in our intermediate _ids structure
  19. // with the documents found by query
  20. assignRawDocsToIdStructure(o.rawIds, o.rawDocs, o.rawOrder, populateOptions);
  21. // now update the original documents being populated using the
  22. // result structure that contains real documents.
  23. const docs = o.docs;
  24. const rawIds = o.rawIds;
  25. const options = o.options;
  26. const count = o.count && o.isVirtual;
  27. function setValue(val) {
  28. if (count) {
  29. return val;
  30. }
  31. if (o.justOne === true && Array.isArray(val)) {
  32. return valueFilter(val[0], options, populateOptions);
  33. } else if (o.justOne === false && !Array.isArray(val)) {
  34. return valueFilter([val], options, populateOptions);
  35. }
  36. return valueFilter(val, options, populateOptions);
  37. }
  38. for (let i = 0; i < docs.length; ++i) {
  39. const existingVal = utils.getValue(o.path, docs[i]);
  40. if (existingVal == null && !getVirtual(o.originalModel.schema, o.path)) {
  41. continue;
  42. }
  43. let valueToSet;
  44. if (count) {
  45. valueToSet = numDocs(rawIds[i]);
  46. } else if (Array.isArray(o.match)) {
  47. valueToSet = Array.isArray(rawIds[i]) ?
  48. sift(o.match[i], rawIds[i]) :
  49. sift(o.match[i], [rawIds[i]])[0];
  50. } else {
  51. valueToSet = rawIds[i];
  52. }
  53. // If we're populating a map, the existing value will be an object, so
  54. // we need to transform again
  55. const originalSchema = o.originalModel.schema;
  56. const isDoc = get(docs[i], '$__', null) != null;
  57. let isMap = isDoc ?
  58. existingVal instanceof Map :
  59. utils.isPOJO(existingVal);
  60. // If we pass the first check, also make sure the local field's schematype
  61. // is map (re: gh-6460)
  62. isMap = isMap && get(originalSchema._getSchema(o.path), '$isSchemaMap');
  63. if (!o.isVirtual && isMap) {
  64. const _keys = existingVal instanceof Map ?
  65. Array.from(existingVal.keys()) :
  66. Object.keys(existingVal);
  67. valueToSet = valueToSet.reduce((cur, v, i) => {
  68. cur.set(_keys[i], v);
  69. return cur;
  70. }, new Map());
  71. }
  72. if (o.isVirtual && isDoc) {
  73. docs[i].populated(o.path, o.justOne ? originalIds[0] : originalIds, o.allOptions);
  74. // If virtual populate and doc is already init-ed, need to walk through
  75. // the actual doc to set rather than setting `_doc` directly
  76. mpath.set(o.path, valueToSet, docs[i], setValue);
  77. continue;
  78. }
  79. const parts = o.path.split('.');
  80. let cur = docs[i];
  81. for (let j = 0; j < parts.length - 1; ++j) {
  82. if (cur[parts[j]] == null) {
  83. cur[parts[j]] = {};
  84. }
  85. cur = cur[parts[j]];
  86. // If the property in MongoDB is a primitive, we won't be able to populate
  87. // the nested path, so skip it. See gh-7545
  88. if (typeof cur !== 'object') {
  89. return;
  90. }
  91. }
  92. if (docs[i].$__) {
  93. docs[i].populated(o.path, o.allIds[i], o.allOptions);
  94. }
  95. // If lean, need to check that each individual virtual respects
  96. // `justOne`, because you may have a populated virtual with `justOne`
  97. // underneath an array. See gh-6867
  98. utils.setValue(o.path, valueToSet, docs[i], setValue, false);
  99. }
  100. };
  101. function numDocs(v) {
  102. if (Array.isArray(v)) {
  103. return v.length;
  104. }
  105. return v == null ? 0 : 1;
  106. }
  107. /*!
  108. * 1) Apply backwards compatible find/findOne behavior to sub documents
  109. *
  110. * find logic:
  111. * a) filter out non-documents
  112. * b) remove _id from sub docs when user specified
  113. *
  114. * findOne
  115. * a) if no doc found, set to null
  116. * b) remove _id from sub docs when user specified
  117. *
  118. * 2) Remove _ids when specified by users query.
  119. *
  120. * background:
  121. * _ids are left in the query even when user excludes them so
  122. * that population mapping can occur.
  123. */
  124. function valueFilter(val, assignmentOpts, populateOptions) {
  125. if (Array.isArray(val)) {
  126. // find logic
  127. const ret = [];
  128. const numValues = val.length;
  129. for (let i = 0; i < numValues; ++i) {
  130. const subdoc = val[i];
  131. if (!isPopulatedObject(subdoc) && (!populateOptions.retainNullValues || subdoc != null)) {
  132. continue;
  133. }
  134. maybeRemoveId(subdoc, assignmentOpts);
  135. ret.push(subdoc);
  136. if (assignmentOpts.originalLimit &&
  137. ret.length >= assignmentOpts.originalLimit) {
  138. break;
  139. }
  140. }
  141. // Since we don't want to have to create a new mongoosearray, make sure to
  142. // modify the array in place
  143. while (val.length > ret.length) {
  144. Array.prototype.pop.apply(val, []);
  145. }
  146. for (let i = 0; i < ret.length; ++i) {
  147. val[i] = ret[i];
  148. }
  149. return val;
  150. }
  151. // findOne
  152. if (isPopulatedObject(val)) {
  153. maybeRemoveId(val, assignmentOpts);
  154. return val;
  155. }
  156. if (val instanceof Map) {
  157. return val;
  158. }
  159. if (populateOptions.justOne === true) {
  160. return (val == null ? val : null);
  161. }
  162. if (populateOptions.justOne === false) {
  163. return [];
  164. }
  165. return val;
  166. }
  167. /*!
  168. * Remove _id from `subdoc` if user specified "lean" query option
  169. */
  170. function maybeRemoveId(subdoc, assignmentOpts) {
  171. if (assignmentOpts.excludeId) {
  172. if (typeof subdoc.setValue === 'function') {
  173. delete subdoc._doc._id;
  174. } else {
  175. delete subdoc._id;
  176. }
  177. }
  178. }
  179. /*!
  180. * Determine if `obj` is something we can set a populated path to. Can be a
  181. * document, a lean document, or an array/map that contains docs.
  182. */
  183. function isPopulatedObject(obj) {
  184. if (obj == null) {
  185. return false;
  186. }
  187. return Array.isArray(obj) ||
  188. obj.$isMongooseMap ||
  189. obj.$__ != null ||
  190. leanPopulateMap.has(obj);
  191. }