Collection.remove({_id: document._id}) VS Collection.remove(document)


#1
1)    Collection.remove({_id: document._id})   

VS

2)    Collection.remove(document)

Example 1 works regardless of whether my _id is stored as an integer:
"_id" : “bf3MEag33cvQYKFYZ”,
or as an object id:
"_id" : ObjectId(“5509dd46ef06e6212c8c1dfe”),

however, example 2 only works when my _id is stored as an integer.

I noticed this because my collection (at the moment) has a mixture of documents indexed with ObjectIds and without ObjectIds… and my remove was only able to remove the ones indexed with integers until I changed it to be like example 1.

Any comments? is this what is expected? Any suggestions on whether I should use version 1 or 2 of the remove call, and whether I should index my documents with ObjectIds or without?

Thanks.


#2

Collection.remove takes the first parameter (the selector) and passes it through the following function:

Mongo.Collection._rewriteSelector = function (selector) {
  // shorthand -- scalars match _id
  if (LocalCollection._selectorIsId(selector))
    selector = {_id: selector};

  if (!selector || (('_id' in selector) && !selector._id))
    // can't match anything
    return {_id: Random.id()};

  var ret = {};
  _.each(selector, function (value, key) {
    // Mongo supports both {field: /foo/} and {field: {$regex: /foo/}}
    if (value instanceof RegExp) {
      ret[key] = convertRegexpToMongoSelector(value);
    } else if (value && value.$regex instanceof RegExp) {
      ret[key] = convertRegexpToMongoSelector(value.$regex);
      // if value is {$regex: /foo/, $options: ...} then $options
      // override the ones set on $regex.
      if (value.$options !== undefined)
        ret[key].$options = value.$options;
    }
    else if (_.contains(['$or','$and','$nor'], key)) {
      // Translate lower levels of $and/$or/$nor
      ret[key] = _.map(value, function (v) {
        return Mongo.Collection._rewriteSelector(v);
      });
    } else {
      ret[key] = value;
    }
  });
  return ret;
};

// Is this selector just shorthand for lookup by _id?
LocalCollection._selectorIsId = function (selector) {
  return (typeof selector === "string") ||
    (typeof selector === "number") ||
    selector instanceof LocalCollection._ObjectID;
};

According to this, you should test some of your ids to see if they pass instanceof LocalCollection._ObjectID and if not, the _id might actually be getting randomized and not matched (coincidentally).

By the way, how come do you have object id’s in your collections? Are those documents created from an outside application? Because it will create a lot of problems. And some of those are design decisions. See this:


#3

Thanks… Yes, I loaded up my mongo collections using PHP’s mongo functions, and that’s what I got by default… but I will look at how to force it to not create objectids if that’s what is recommended…??


#4

create 17 character random alfanumeric strings

I think there is a safe caharcters array somewhere in meteor that constitute the characters that may appear in an id. check the source code for the random package.

it is used in meteor to create random unique ids and should be fairly easy to implement in php.


#5

I’m new to mongo and meteor so I’m learning this as I go… I’m confused as to why the default behavior in Meteor, when doing an insert without an _id, is to use just a string, but when doing an insert through the mongo command line interface (and when doing an insert via the PHP mongo package) the default is to create an ObjectId with a random string.

And then you said that using ObjectIds will create a lot of problems…

Also, I looked at the PHP mongo .insert function and it seems that there isn’t an option to force it to not use ObjectId.

It seems odd that my only solution is to implement my own method to generate 17 character strings… especially since that only helps with my php batch load and wouldn’t help if I (for some reason) needed to do an insert via the command line…


#6

Solved the issue. In my php script that loads the mongo collection, instead of leaving _id blank and letting it assign an ObjectId to the _id field, I use the MongoId constructor to create the unique id, then cast it to a string before inserting into the collection:

  $theId = new MongoId();
  $extra['_id'] = (string)$theId;
  $chart->insert(array_merge($extra, $theArray));