mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Disallow {fields:{_id:0}} in observeChanges
This implies it is not allowed in `observe` either, or in cursors
returned from publish functions, or in cursors used in {{#each}}
Why? observeChanges and DDP publication use the ID as part of the
callback/message, and eliding it completely breaks them. Meteor UI uses
the ID with {{#each}} to properly move nodes around instead of
re-rendering. We could try to allow it for `observe` outside of
{{#each}}, but it would feel somewhat inconsistent.
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
* Hash login tokens before storing them in the database.
|
||||
|
||||
* Cursors with a field specifier containing `{_id: 0}` can no longer be used
|
||||
with `observeChanges` or `observe`. This includes the implicit calls to these
|
||||
functions that are done when returning a cursor from a publish function or
|
||||
using `{{#each}}`.
|
||||
|
||||
## v0.7.0.1
|
||||
|
||||
|
||||
@@ -1319,21 +1319,32 @@ it's up to you to be sure.
|
||||
Queries can specify a particular set of fields to include or exclude from the
|
||||
result object.
|
||||
|
||||
To exclude certain fields from the result objects, the field specifier
|
||||
is a dictionary whose keys are field names and whose values are `0`.
|
||||
To exclude specific fields from the result objects, the field specifier is a
|
||||
dictionary whose keys are field names and whose values are `0`. All unspecified
|
||||
fields are included.
|
||||
|
||||
// Users.find({}, {fields: {password: 0, hash: 0}})
|
||||
|
||||
To return an object that only includes the specified field, use `1` as
|
||||
To include only specific fields in the result documents, use `1` as
|
||||
the value. The `_id` field is still included in the result.
|
||||
|
||||
// Users.find({}, {fields: {firstname: 1, lastname: 1}})
|
||||
|
||||
It is not possible to mix inclusion and exclusion styles (except for the cases
|
||||
when `_id` is included by default or explicitly excluded). Field operators such
|
||||
as `$` and `$elemMatch` are not available on the client side yet.
|
||||
With one exception, it is not possible to mix inclusion and exclusion styles:
|
||||
the keys must either be all 1 or all 0. The exception is that you may specify
|
||||
`_id: 0` in an inclusion specifier, which will leave `_id` out of the result
|
||||
object as well. However, such field specifiers can not be used with
|
||||
[`observeChanges`](#observe_changes), [`observe`](#observe), cursors returned
|
||||
from a [publish function](#meteor_publish), or cursors used in
|
||||
`{{dstache}}#each}}` in a template. They may be used with [`fetch`](#fetch),
|
||||
[`findOne`](#findone), [`forEach`](#foreach), and [`map`](#map).
|
||||
|
||||
More advanced example:
|
||||
|
||||
<a href="http://docs.mongodb.org/manual/reference/operator/projection/">Field
|
||||
operators</a> such as `$` and `$elemMatch` are not available on the client side
|
||||
yet.
|
||||
|
||||
A more advanced example:
|
||||
|
||||
Users.insert({ alterEgos: [{ name: "Kira", alliance: "murderer" },
|
||||
{ name: "L", alliance: "police" }],
|
||||
|
||||
@@ -270,6 +270,9 @@ _.extend(LocalCollection.Cursor.prototype, {
|
||||
if (!options._allow_unordered && !ordered && (self.skip || self.limit))
|
||||
throw new Error("must use ordered observe with skip or limit");
|
||||
|
||||
if (self.fields && (self.fields._id === 0 || self.fields._id === false))
|
||||
throw Error("You may not observe a cursor with {fields: {_id: 0}}");
|
||||
|
||||
var query = {
|
||||
matcher: self.matcher, // not fast pathed
|
||||
sorter: ordered && self.sorter,
|
||||
|
||||
@@ -1432,6 +1432,14 @@ Tinytest.add("minimongo - observe ordered with projection", function (test) {
|
||||
c.insert({_id: idA2, a:2});
|
||||
test.equal(operations.shift(), undefined);
|
||||
|
||||
var cursor = c.find({}, {fields: {a: 1, _id: 0}});
|
||||
test.throws(function () {
|
||||
cursor.observeChanges({added: function () {}});
|
||||
});
|
||||
test.throws(function () {
|
||||
cursor.observe({added: function () {}});
|
||||
});
|
||||
|
||||
// test initial inserts (and backwards sort)
|
||||
handle = c.find({}, {sort: {a: -1}, fields: { a: 1 } }).observe(cbs);
|
||||
test.equal(operations.shift(), ['added', {a:2}, 0, null]);
|
||||
|
||||
@@ -957,6 +957,14 @@ MongoConnection.prototype._observeChanges = function (
|
||||
return self._observeChangesTailable(cursorDescription, ordered, callbacks);
|
||||
}
|
||||
|
||||
// You may not filter out _id when observing changes, because the id is a core
|
||||
// part of the observeChanges API.
|
||||
if (cursorDescription.options.fields &&
|
||||
(cursorDescription.options.fields._id === 0 ||
|
||||
cursorDescription.options.fields._id === false)) {
|
||||
throw Error("You may not observe a cursor with {fields: {_id: 0}}");
|
||||
}
|
||||
|
||||
var observeKey = JSON.stringify(
|
||||
_.extend({ordered: ordered}, cursorDescription));
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ _.each ([{added:'added', forceOrdered: true},
|
||||
function (logger) {
|
||||
var barid = c.insert({thing: "stuff"});
|
||||
var fooid = c.insert({noodles: "good", bacon: "bad", apples: "ok"});
|
||||
|
||||
var handle = c.find(fooid).observeChanges(logger);
|
||||
if (added === 'added')
|
||||
logger.expectResult(added, [fooid, {noodles: "good", bacon: "bad",apples: "ok"}]);
|
||||
@@ -43,6 +44,12 @@ _.each ([{added:'added', forceOrdered: true},
|
||||
c.insert({noodles: "good", bacon: "bad", apples: "ok"});
|
||||
logger.expectNoResult();
|
||||
handle.stop();
|
||||
|
||||
var badCursor = c.find({}, {fields: {noodles: 1, _id: false}});
|
||||
test.throws(function () {
|
||||
badCursor.observeChanges(logger);
|
||||
});
|
||||
|
||||
onComplete();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user