Can meteor mongo driver handle $each and $position operators?
Asked Answered
T

1

17

I work on a meteor application with meteor bundle up to date. I want to reposition an item within a mongo document array. To achieve that, I $pull it out of the array, and then $push it at a specific index position according to mongoDB documentation.

MyCollection.update({_id: my_doc.id},
        {
          $push:
          {
            my_array:
            {
              $each:[my_item.id],
              $position:index
            }
          }
        }
      )

Meteor/Mongo throws the following error:

update failed: MongoError: Can't canonicalize query: BadValue unknown top level operator: $each

I first implemented this client side. I assumed it didn't work because of minimongo limitations.

I wrote a method to handle this server side, but I end up with the same error.

What is wrong with this request, can meteor handle the $each operator?


EDIT : I tried to insert it directly in robomongo, and it worked. Mongo version, when typing db.version() returns 2.6.7


*EDIT2 : I did not expect it so I didn't check before: the update works, both with the $pull and the $push. However, even if the data is actually updated, I still get the error.


*EDIT : Here is some example data:

{
    "_id" : "oSNrpgAAu8BuznvD6",
    "name" : "tynhjderjye",
    "description" : "",
    "notes" : "",
    "display_notes" : false,
    "keywords" : [
        ""
    ],
    "owner" : "mA5Y7LBCoRyeSDkaG",
    "createdAt" : ISODate("2015-10-27T13:59:06.083Z"),
    "createdBy" : "C3i9oj4eapyttHZj6",
    "contributors" : [
        "C3i9oj4eapyttHZj6"
    ],
    "medias" : [
        "TcFqermNY4y5cjBG3",
        "dbkNN2rxXJXth8urw",
        "jML4JKkRoKxx8sLwu",
        "LEWYsnPrXRSH6MPkX"
    ],
    "modifiedAt" : ISODate("2015-11-17T09:35:50.303Z"),
    "modifiedBy" : "C3i9oj4eapyttHZj6",
    "chunks" : [
        "qCCHKJDbdTLEFR5Yt",
        "ySiM7dcxvduEM2npj",
        "5q46vqrmYttscitiK"
    ],
    "trashed" : ISODate("2015-11-17T09:35:50.303Z")
}

chunks is the array my_array where I pull and push the my_item.id at the position index

Theriot answered 14/12, 2015 at 14:46 Comment(8)
What's the version of your MongoDB server?Lithe
Try to execute the same command in the mongo shell client.Beneficiary
@DmytroShevchenko The same command works fine in RoboMongo (equivalent to shell client I guess).Theriot
@Theriot if the command works against the same server in RoboMongo, then the problem is with Meteor's MongoDB driver and not with the server's version.Beneficiary
I updated the question title and content accordinglyTheriot
How did you $pull the element from the array? What is my_item?Xenogamy
I pull it in a different command and I do it by the book. The $pull has been tested separately and works fine.Theriot
I'd actually create an admin panel and do what you're trying to achieve with a few methods, helpers & events (if what you want is the admin's job). If not, I'd still do the same thing on the client side. Don't know your case though. If thats what you decide to do, I can write an answer.Daughterinlaw
V
5

If you create a Meteor Collection with new Mongo.Collection('col') you get back a Minimongo instance which is not the native Node MongoDriver, right?

So some methods just don't work or not fully supported.. like collection.aggregate

But you can easily access the native driver via Col.rawCollection() and perform your query directly on the native instance. The native instance is only accessible on the server, of course.

So to do what you want do you have several ways, for example you could first take the array, resort it how you want and

$set: {my_array: sortedArray } Personally I would prefer this way because you need to do only one update operation instead of two ($pull & $push at $position)

But if you want to do it the $push at $position way.. just do it with the native driver

var col = Collection.rawCollection();
var result = Meteor.wrapAsync(col.update.bind(col)(
  /* update query goes here */
);

Note: You need the Meteor.wrapAsync because of Meteor sync style, you could also do it with out it. Collection.rawCollection().update(...)

Vincenty answered 22/12, 2015 at 19:37 Comment(3)
Thank you for the tip about using the native mongo driver from meteor. However, this is not working. I don't get it. Same error with your technique. It seems that the id in the $each is the cause. However, I checked its type (string) with and without putting it in an array, I checked that it matches a real content in database, and finally I checked it in a direct mongo request. Mongo request works, the update command from meteor with the code in my question works, but it still triggers the error mentioned there (with or without your rawCollection() technique).Theriot
I will probably switch to an approach with $set and replace the whole array and it will probably solve the problem. However, I still don't know why this error occurs and it is bugging me :-)Theriot
Sorry for letting the bounty spoil, I assume you had half of it awarded. I won't mark this answer as accepted in case someone shows up with the real answer. Thanks to you and all commenters for the help.Theriot

© 2022 - 2024 — McMap. All rights reserved.