2

I'm getting this error:

"Unrecognized logical operator: $in"

while using this query:

this.update(
            {}, {
                $pull: {
                    words: {
                        $in:['string', 'string1']
                    }
                }
            }, {
                multi: true
            });

I'm calling within a es6 class that extends Mongo.Collection in the client, everything else thus far (inserts, remove) has worked and I'm not modifying the update method in any way. The collection is a local collection declared this way:

WordsList = new WordCollection('words', {connection: null});)

The query is very similar to the example in the documentation here and actually, I can reproduce the same error while trying to recreate this example on the console as well.

I'm using Meteor 1.4.4.1 with MongoDB 3.2.12

For some reason I can't yet pin down, I can trace the error to Mongo compiling the query mapping it to logical operators ($and, $or) instead of element (comparison query) operators ($in, $eq)

lvlzqz
  • 33
  • 6
  • 1
    I don't think meteor allows that kind of update without an specific document `_id`. Also, may not work in Minimongo in the browser client, but this is valid syntax "server side". So maybe you should use a server method. – Neil Lunn Jun 18 '17 at 00:51
  • Well the example in the docs doesn't pass an id, it is meant to apply to all matching documents. Also (forgot to mention) this is a client side collection (passing {connection: null} as second argument), will update this in the post. – lvlzqz Jun 18 '17 at 00:58
  • I think you are confusing documentation sources here. MongoDB core documentation lists the correct syntax options for `$pull` and this is a valid statement. Meteor [`.update()`](https://docs.meteor.com/api/collections.html#Mongo-Collection-update) as implemented considers "untrusted" client code to not be valid when not including a specific document `_id`. Unless you specifically secured the method, it would not be allowed. I think you really need to execute this as a [Server method](https://guide.meteor.com/methods.html) – Neil Lunn Jun 18 '17 at 01:02
  • Also I deliberately removed the MongoDB tag because the syntax in this case is actually Meteor specific. As a query to MongoDB alone, it's perfectly valid. – Neil Lunn Jun 18 '17 at 01:04
  • So this is a [local collection](https://guide.meteor.com/collections.html#local-collections), it only exists in the client side, so calling it from the server wouldn't really work for this scenario :( also insert and remove methods work which wouldn't work for the security reasons you mention if this in fact was a collection in the server – lvlzqz Jun 18 '17 at 01:16
  • also what do you mean by securing the method? @NeilLunn – lvlzqz Jun 18 '17 at 01:17
  • It's all described in the meteor documentation links I have already given. If you are not familiar with the terms, then you should become familiar. Read the documentation for all the detail. – Neil Lunn Jun 18 '17 at 02:27
  • Got it. This is a local collection so your approach really does not apply, thanks anyway – lvlzqz Jun 18 '17 at 03:55

1 Answers1

2

It is possible to modify multiple values in a local collection, however there is a limitation in what selectors or modifiers can be used, as the client-side collection users MiniMongo, which implements a subset of the MongoDB functionality.

This particular case is a shortcoming of MiniMongo, where a logical Matcher is used in $pull expressions, as indicated in a comment in the $pull implementation:

    // XXX Minimongo.Matcher isn't up for the job, because we need
    // to permit stuff like {$pull: {a: {$gt: 4}}}.. something
    // like {$gt: 4} is not normally a complete selector.
    // same issue as $elemMatch possibly?

(source: Meteor source code)

This is from 2013, so there is not much hope for it to change without a PR.

Specifically, the matcher only allows you to use logical selectors: "$and", "$or", "$nor", "$where", "$comment". That's why you cannot use $in, which is implemented in ELEMENT_OPERATORS.

As a workaround (and since this is only client-side), you can use:

valueArray.forEach(val => WordsList.update({}, {$pull: {words: val}}, {multi: true}));
MasterAM
  • 16,283
  • 6
  • 45
  • 66
  • Thank you for this! I unfortunately don't have yet enough reputation to vote you up but you articulated the culprit and provided a working solution. – lvlzqz Jun 18 '17 at 19:09
  • Keep asking good questions and you soon will :) Anyway, if this answer solved the problem you can accept the answer. – MasterAM Jun 18 '17 at 19:12
  • Looks like I'm getting pretty close! – lvlzqz Jun 18 '17 at 19:59