6

From my website client I am sending an API request to the backend Node.js server and finding a specific document by ID like so:

var ObjectID = require('mongodb').ObjectID;   

db.collection('users').find({"_id": new ObjectID(req.body._id)})

Where req.body._id equals the entire ID string, such as '5d0381ad681a2a3aa1dc5872'

However I would prefer to send only the INC (ever incrementing value) portion of the string as the argument: 'c5872'

How should I find a specific document based on just the INC value? (I'm assuming the INC is unique)

Any help is greatly appreciated.

mobiman
  • 619
  • 1
  • 11
  • 26

2 Answers2

3

You can temporarily transform your _id using in a string to be able to use a regular expression :

db.users.aggregate([
  {
    $addFields: { id: { $toString: '$_id' } }
  },
  {
    $match: { id: /c5872$/ }
  }
])

A cleaner solution is to create the field directly with a substring to avoid using a regular expression :

db.users.aggregate([
  {
    $addFields: { id: { $substr: [{ $toString: '$_id' }, 19, 24] } }
  },
  {
    $match: { id: 'c5872' }
  }
])

https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/ https://docs.mongodb.com/manual/reference/operator/aggregation/substr/

Romain Simon
  • 151
  • 6
  • Hi, it does look clean, in the other hand the documentation said: Place the `$match` as early in the aggregation pipeline as possible. Because `$match` limits the total number of documents in the aggregation pipeline, earlier `$match` operations minimize the amount of processing down the pipe. – Haniel Baez Apr 20 '21 at 22:25
  • @HanielBaez Yes, the `$addFields` operation will be done on the entire collection but this needs to be done before applying the `$match`. If the collection is large, it is preferable to really create the field in the database in order to have an index on the field, as you suggested in your answer. – Romain Simon Apr 21 '21 at 12:47
1

You could create an additional ID field and a unique index to ensure that indexed fields do not store duplicate values, but note that for a five hex string, we have "1,048,576" possible combinations (16 ^ 5 = 1048576).

Note: Using a regular expression could lead to a collection scan.

A regular expression is a "prefix expression" if it starts with a caret (^) or a left anchor (\A), followed by a string of simple symbols. For example, the regex /^abc.*/ will be optimized by matching only against the values from the index that start with abc.

Regular expression and index use

Haniel Baez
  • 1,646
  • 14
  • 19
  • Using 6 characters instead of 5 is fine for me. – mobiman Apr 20 '21 at 18:41
  • Isn't the _id field automatically generated by MongoDB already unique? Or are you suggesting creating an additional ID field in order to avoid a collection scan? – mobiman Apr 20 '21 at 18:44
  • Yes, the _id is unique. What I said is that, you should be caution when using regex, it can lent to a collection scan. – Haniel Baez Apr 20 '21 at 22:14
  • But it will only lead to a collection scan if no value stored in MongoDB can satisfy the query. But in that case even if I create an additional ID field (no regex) I run the risk of a collection scan correct? – mobiman Apr 20 '21 at 23:46
  • Hmmm... I think I understand what you mean. By creating an additional ID field we can put an index on that field. Thus avoiding the potential for a collection scan – mobiman Apr 20 '21 at 23:59
  • If the field is indexed, and not value can satisfy the query, the worst thing that could happen, is an index scan (not that bad). – Haniel Baez Apr 21 '21 at 01:12