簡體   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