mongodb get _id as string in find query

后端 未结 3 2121
死守一世寂寞
死守一世寂寞 2020-12-03 18:48

Here I have created a collection with a single document

db.getCollection(\'example\').insert({\"example\":1});

I have tried to use Projecti

3条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-03 19:02

    MongoDB 4.0 adds the $convert aggregation operator and the $toString alias which allows you to do exactly that:

    db.getCollection('example').aggregate([
      { "$match": { "example":1 } },
      { "$project": { "_id": { "$toString": "$_id" } } }
    ])
    

    A main usage would most likely be though to use the _id value as a "key" in a document.

    db.getCollection('example').insertOne({ "a": 1, "b": 2 })
    
    db.getCollection('example').aggregate([
      { "$replaceRoot": {
        "newRoot": {
          "$arrayToObject": [
            [{ 
              "k": { "$toString": "$_id" },
              "v": {
                "$arrayToObject": {
                  "$filter": {
                    "input": { "$objectToArray": "$$ROOT" },
                    "cond": { "$ne": ["$$this.k", "_id"] }
                  }
                }
              }
            }] 
          ]
        }
      }}
    ])
    

    Which would return:

    { 
      "5b06973e7f859c325db150fd" : { "a" : 1, "b" : 2 }
    }
    

    Which clearly shows the string, as does the other example.

    Generally though there is usually a way to do "transforms" on the cursor as documents are returned from the server. This is usually a good thing since an ObjectId is a 12-byte binary representation as opposed to a 24 character hex "string" which takes a lot more space.

    The shell has a .map() method

    db.getCollection('example').find().map(d => Object.assign(d, { _id: d._id.valueOf() }) )
    

    And NodeJS has a Cursor.map() which can do much the same thing:

    let cursor = db.collection('example').find()
        .map(( _id, ...d }) => ({ _id: _id.toString(), ...d }));
    
    while ( await cursor.hasNext() ) {
      let doc = cursor.next();
      // do something
    })
    

    And the same method exists in other drivers as well ( just not PHP ), or you can just iterate the cursor and transform the content as is more likely the best thing to do.


    In fact, whole cursor results can be reduced into a single object with great ease by simply adding to any cursor returning statement, when working in the shell

    .toArray().reduce((o,e) => { 
      var _id = e._id;
      delete e._id;
      return Object.assign(o, { [_id]: e })
    },{ })
    

    Or for full ES6 JavaScript supporting environments like nodejs:

    .toArray().reduce((o,({ _id, ...e })) =>  ({ ...o, [_id]: e }),{ })
    

    Really simple stuff without the complexity of what needs to process in the aggregation framework. And very possible in any language by much the same means.

提交回复
热议问题