繁体   English   中英

mongoose.find() 方法返回具有不需要的属性的 object

[英]mongoose .find() method returns object with unwanted properties

所以,我一直在使用 mongoose 一段时间,我发现了一些非常奇怪的事情。 如果有人能启发我,那就太好了。

问题是,当使用 mongoose 的 .find() 方法时,我得到的 object 响应充满了我不知道它来自哪里的属性(我猜它们是内置属性,但无论如何)和我只想遍历属性 I.select()。 知道了? 不? 好的...解释得更好:

我有我的架构和 model 声明:

var mySchema = mongoose.Schema({
  name: String,
  prop1: String,
  prop2: String,
  prop3: String
})
var myModel = DB.model('myDataBase', mySchema)

然后我想找到一个名称为 John 的文档,并检索除“name”字段之外的所有字段,因此我使用 go:

myModel.find({name: 'John'}, '-name', function(err, results){
  log(results[0])
}

和 log(results[0]) 日志

{ prop1: 'one',
  prop2: 'two',
  prop3: 'three' }

到目前为止,一切都很好。 但问题是,现在我想遍历这些属性并一一检查,我不确定每个结果会有多少“道具”,所以我想做类似的事情:

for(var key in results[0]){
  log(key)
}

所以,我希望它会记录“prop1”、“prop2”和“prop3”,但不,好的,我得到了道具 1、2 和 3:但我也得到了很多其他属性和函数,比如 isNew,错误,_maxListeners,_doc。 等等,不仅这些额外属性,我还获得了“名称”属性,即我从选择中排除的那个(它被排除在外。如第一个日志中所示)? 很奇怪吧?

但是等等,还有更多。 我在网上搜索过,发现有人说“老兄:在遍历 object 属性时使用 hasOwnProperty 方法!”。 所以我去了:

for (var key in results[0]){
  if (results[0].hasOwnProperty(key)) log(key)
}

日志结果是一些属性(具体来说:$__、isNew、error、_maxListeners、_doc、_pres、_posts、save、_events)并且不包括我想要的任何道具。

我的问题是,我怎样才能只遍历道具 1、2 和 3,不包括这些,我不知道,内置属性和我在参数中明确排除的属性? (ps:如果可能的话,我正在考虑一个不需要将我的 object 转换为数组的解决方案)

此外,这本身不是一个问题,而是出于好奇,这些属性从何而来? 为什么它们出现在 for 循环中,而不是在我记录 object 时? 为什么我排除的属性('-name')也出现在 for 循环中? 如果 hasOwnProperty 不能识别刚刚记录的属性,它到底是什么?

感谢您的时间和帮助! 再见!

除了凯文 B 的答案,您可以将{lean: true}作为选项传递:

myModel.find({name: 'John'}, '-name', {lean: true}, function(err, results){
  log(results[0])
}

在 MongoDB 中,文档被简单地保存为对象。 当 Mongoose 检索它们时,它会将它们转换为 Mongoose 文档。 这样做时,它会添加所有包含在for循环中的键。 这就是允许您使用所有文档方法的原因。 如果您不会使用其中任何一个, lean是一个很好的选择,因为它跳过了整个过程,提高了查询速度。 可能快 3 倍。

在这种情况下, .toObject 足以让您的循环按您期望的方式工作。

myModel.find({name: 'John'}, '-name', function(err, results){
  log(results[0].toObject())
}

您最初获得的额外属性是因为results是一组模型实例,这些实例带有在普通对象上不可用的其他属性和方法。 这些属性和方法是您的循环中出现的内容。 通过使用toObject ,您可以获得一个没有所有这些附加属性和方法的普通对象。

答案很好,我想添加一个我添加到 dbUtils 类中的小打字稿实用程序。

getCleanObjectFromObjectOrDocument<T>(obj: T): T {
        return ((obj as unknown) as Document)?.toObject?.() ?? obj;
}

您可以在此处传递 mongoose 文档/子文档或任何普通 JS 对象,它会返回相应的 JS 对象。

在 mongo 查询上使用myModel.find().lean()或传递 {lean:true} 参数,例如myModel.find().lean()

TLDR: toObject()lean()是获得 JavaScript object 所需的 2 种方法,前面的答案指出了这一点。 我的答案有一个完整的例子来说明这个概念以及如何使用它们。


When you use Mongoose API to query data (find, findOne, findById..), Mongoose will give you an instance of Mongoose Document class in the response, which is different from your Javascript object .

您有一些选项来获取 Javascript object,如文档中所述:

  • 使用lea()方法:在此处查看文档
  • 使用toObject()方法:在此处查看文档

我创建了一个测试项目来演示这些方法,请随意测试:

const mongoose = require('mongoose');

// connect to database
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true });

// define the schema 
const kittySchema = new mongoose.Schema({
    name: String

    // this flag indicate that the shema we defined is not fixed, 
    // document in database can have some fields that are not defined in the schema
    // which is very likely
}, { strict: false });

// compile schema to model
const Kitten = mongoose.model('Kitten', kittySchema);

test();
async function test() {


    // test data
    const dataObject = { name: "Kitty 1", color: "red" };
    const firstKitty = new Kitten(dataObject); // attribute color is not defined in the schema

    // save in database
    firstKitty.save();

    // find the kitty from database
    // mongoose return a document object, which is different from our data object
    const firstKittyDocument = await Kitten.findOne({ name: "Kitty 1" });
    console.log("Mongoose document. _id :", firstKittyDocument._id); // _id of document
    console.log("Mongoose document. name :", firstKittyDocument.name); // "Kitty 1"
    console.log("Mongoose document. color :", firstKittyDocument.color); // undefined
    // --> the document contains _id and other fields that we defined in the schema

    // we can call the method .toObject to get the plain object
    console.log("Using .toObject() method. _id :", firstKittyDocument.toObject()._id); // _id of document
    console.log("Using .toObject() method. name :", firstKittyDocument.toObject().name); // "Kitty 1"
    console.log("Using .toObject() method. color :", firstKittyDocument.toObject().color); // "red"
    // --> Using .toObject() method, we get all the fields we have in the dataObject

    // or we can use lean method to get the plain old javascript object
    const firstKittyPOJO = await Kitten.findOne({ name: "Kitty 1" }).lean();
    console.log("Using .lean() method. _id :", firstKittyPOJO._id);  // _id of document
    console.log("Using .lean() method. name :", firstKittyPOJO.name); // "Kitty 1"
    console.log("Using .lean() method. color :", firstKittyPOJO.color); //"red"
    // --> Using .lean() method, we get all the fields we have in the dataObject
}

附带说明,当您使用lea lean()方法时,Mongoose 会跳过将 JavaScript object 转换为 ZCADCDEDB567ABAE643E15EDF 文档的步骤,从而为您的查询带来更好的性能

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM