Mongoose: Model.save() tidak menyimpan array yang disematkan

Dibuat pada 10 Nov 2012  ·  26Komentar  ·  Sumber: Automattic/mongoose

Saya memiliki kumpulan dokumen bersarang, dan ketika saya mengubahnya dan melakukan .save() pada model itu tidak menyimpan perubahan dalam dokumen bersarang.

Berikut adalah model dan skema saya (beberapa dihilangkan untuk singkatnya):

var Votes = new mongoose.Schema({
    date: Date, 
    user_name: String,
    is_up: Boolean
});

var EventSchema = new mongoose.Schema({
  to_date: Date,
  from_date: Date,
  location: String,
  name: String,
  suggested_by: String,
  description: String,
  users: [EventUser],
  comments: [Comments],
  suggestions: [Event],
  votes: [Votes]
});

var Event = mongoose.model('Event', EventSchema);

Model sebelum event.save() dipanggil:

{ 
     __v: 1,
    _id: 509e87e583ccbfa00e000004,
    description: 'Pfft',
    from_date: Sun Nov 11 2012 08:00:00 GMT-0500 (EST),
    location: 'Home',
    name: 'Whatever',
    suggested_by: 'No one',
    to_date: Sun Nov 11 2012 00:00:00 GMT-0500 (EST),
    votes: [],
    suggestions: 
     [ { users: [],
         comments: [],
         suggestions: [],
         votes: [],
         _id: 509e880883ccbfa00e000005,
         suggested_by: 'Some one',
         to_date: Sun Nov 11 2012 04:00:00 GMT-0500 (EST),
         from_date: Mon Nov 12 2012 00:00:00 GMT-0500 (EST),
         location: 'Home',
         name: 'Football',
         description: 'FOOTBALL!!' } ],
    comments: [],
    users: [] 
}

Objek yang sama dengan suara bersarang tepat sebelum event.save() dipanggil.

{
   "__v":1,
   "_id":"509e87e583ccbfa00e000004",
   "description":"Pfft",
   "from_date":"2012-11-11T13:00:00.000Z",
   "location":"Home",
   "name":"Whatever",
   "suggested_by":"No one",
   "to_date":"2012-11-11T05:00:00.000Z",
   "votes":[ ],
   "suggestions":
      [ {
         "users":[],
         "comments":[ ],
         "suggestions":[ ],
         "votes":
            [{
               "is_up":true,
               "date":"2012-11-10T18:05:25.796Z",
               "user_name":"No one"
            }],
         "_id":"509e880883ccbfa00e000005",
         "suggested_by":"Some one",
         "to_date":"2012-11-11T09:00:00.000Z",
         "from_date":"2012-11-12T05:00:00.000Z",
         "location":"Home",
         "name":"Football",
         "description":"FOOTBALL!!"
      }],
   "comments":[],
   "users":[]
}

Saat event.save() dipanggil, tidak ada kesalahan yang muncul, tetapi skema suara bersarang di dalam skema peristiwa bersarang sebenarnya tidak disimpan. Jika saya menggunakan logika keseluruhan yang sama di objek acara tingkat atas untuk menyimpan suara, itu berhasil.

Ketika saya melihat melalui kode, secara singkat, tampaknya .save() seharusnya menjadi jalan pintas untuk menyimpan objek baru, serta memperbarui yang sudah ada.

Firasat saya adalah Model.prototype._delta tidak cukup dalam untuk menangkap semua objek bersarang, https://github.com/LearnBoost/mongoose/blob/master/lib/model.js#L529

Komentar yang paling membantu

Saya melihat apa masalahnya - kasus klasik dari pertanyaan pertama di FAQ luwak.

Terima kasih, itu masalah ini dalam kasus saya! :)

model.myArray[index] = anyValue

menjadi

model.myArray.set(index, anyValue)

Semua 26 komentar

Harap sertakan juga kode yang Anda gunakan untuk mereproduksi masalah (di mana Anda memanipulasi dokumen sebelum menyimpan dll)

Tentu, saya mempostingnya di Intisari untuk menghindari dinding kode di sini, https://Gist.github.com/4055392

Saya menyertakan menyimpan suara di acara tingkat atas (berfungsi) serta menyimpannya dalam acara bersarang (tidak berfungsi). Seperti yang Anda lihat, mereka menambahkan atau memperbarui suara dan kemudian menyimpannya dengan cara yang sama.

Coba perbaiki referensi EventSchema Anda yang digunakan di suggestions :

// bad
var EventSchema = new mongoose.Schema({
  suggestions: [EventSchema] <== at this time, EventSchema is undefined which is interpreted as Mixed

// instead...

var EventSchema = new mongoose.Schema;
EventSchema.add({
  suggestions: [EventSchema] <== EventSchema exists
})


menutup, tidak ada jawaban. silahkan buka kembali jika perlu.

Saya memiliki masalah yang sama di mana .save() mengembalikan dokumen yang telah memperbarui objek yang disematkan tetapi sebenarnya tidak disimpan di mongodb. Tolong bantu saya dalam hal ini.

@Manojkumar91 dapatkah Anda memberikan beberapa kode yang mengulangi ini? Akan sangat membantu :)

Saya juga mengalami ini, inilah model saya:

/*jslint node:true */
"use strict";

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var measurement = new Schema({
    name: {type: String, required: true},
    instruction: {type: String, required: true}
});

var size = new Schema({
    name: {type: String, required: true},
    lengths: [String]
});

var chartSchema = new Schema({
    name: {type: String, required: true },
    diagram: {type: String, required: true },
    description: {type: String, required: true},
    totalMeasurements: {type: Number, required: true},
    totalSizes: {type: Number, required: true},
    measurements: [measurement],
    sizes: [size]
});

module.exports = mongoose.model('chart', chartSchema);

Ini adalah bagian dari aplikasi yang jauh lebih besar, jadi saya hanya menyertakan filter tindakan pengontrol yang relevan, tetapi saya dapat berbicara dengan yang lainnya dalam arti yang lebih luas. Di bawah ini adalah kode filternya:

    module.exports = function (next) {
      var paramCounter = 1,
          outerLoopCounter = 0,
          existingSizes = this.chart.sizes.length,
          outerLoopEdge = this.chart.totalSizes,
          innerLoopCounter = 0,
          innerloopEdge = this.chart.totalMeasurements - 1,
          size = {name: null, lengths: [] };

      if (this.req.method && this.req.method === "POST") {
          for (outerLoopCounter;
                  outerLoopCounter < existingSizes;
                  outerLoopCounter = outerLoopCounter + 1) {

              this.chart.sizes[outerLoopCounter].name =
                  this.param("name_" + paramCounter);

              for (innerLoopCounter;
                      innerLoopCounter <= innerloopEdge;
                      innerLoopCounter = innerLoopCounter + 1) {
                  this.chart.sizes[outerLoopCounter].lengths[innerLoopCounter] =
                      this.param(this.chart.measurements[innerLoopCounter].name);
              }
              paramCounter = paramCounter + 1;
              innerLoopCounter = 0;
          }

        for (outerLoopCounter;
                outerLoopCounter < outerLoopEdge;
                outerLoopCounter = outerLoopCounter + 1) {
            size.name = this.param("name_" + paramCounter);
            for (innerLoopCounter;
                    innerLoopCounter < innerloopEdge;
                    innerLoopCounter = innerLoopCounter + 1) {
                size.lengths.push(
                    this.param(this.chart.measurements[innerLoopCounter].name
                               + "_" + paramCounter)
                );
            }
            this.chart.sizes.push(size);
            paramCounter = paramCounter + 1;
            innerLoopCounter = 0;
            size = { name: null, lengths: [] };
        }

        this.chart.save(function (err) {
            if (err) {
                console.log(err);
            }

            this.chart_info = "measurements for <strong>" + this.chart.name + "</strong> saved.";
            this.render("display");
        }.bind(this));
    } else {
        next();
    }
  };

Efeknya, sebelum menjalankan filter ini, filter dipanggil yang membuat struktur formulir yang bergantung pada status berdasarkan larik ukuran dan ukuran 2 dimensi, lalu daftar elemen ini diuraikan untuk memberikan pembaruan. Saya telah menguji dengan data dummy dan grafik dummy saat ini (diambil dari konsol) terlihat seperti ini:

> db.charts.find();
{ "_id" : ObjectId("553da6c3d3d0940a640e878c"), "name" : "Chart With Measurements", "diagram" : "http://res.cloudinary.com/harung71k/image/upload/v1430103747/nd4gipcxnykbbcpcztp9.jpg", "description" : "<p>This is a test of the new measurement methodology, it works.</p>", "totalMeasurements" : 4, "totalSizes" : 3, "sizes" : [ { "name" : "Small", "_id" : ObjectId("554183ed63c5945b73b8a8e7"), "lengths" : [ "1", "2", "3", "4" ] }, { "name" : "Medium", "_id" : ObjectId("554183ed63c5945b73b8a8e8"), "lengths" : [ "5", "6", "7", "8" ] }, { "name" : "Large", "_id" : ObjectId("554183ed63c5945b73b8a8e9"), "lengths" : [ "9", "10", "11", "12" ] } ], "measurements" : [ { "name" : "Fuzz", "instruction" : "<p>Fuzz Instructions</p>", "_id" : ObjectId("553dadd253eb9f996c68a381") }, { "name" : "Buzz", "instruction" : "<p>Buzz Instructions</p>", "_id" : ObjectId("553dadd253eb9f996c68a382") }, { "name" : "Beatles", "instruction" : "<p>Beatles Instructions</p>", "_id" : ObjectId("553dadd253eb9f996c68a383") }, { "name" : "Stones", "instruction" : "<p>Stones instructions</p>", "_id" : ObjectId("553ee7a09ff8c567004bd261") } ], "__v" : 3 }

Saya telah menguji array ukuran yang dimodifikasi tepat sebelum menyimpan, diberi input "1111" di slot size[0].lengths[0] dan ini muncul di dokumen saat diperiksa di Node, tetapi penyimpanannya kembali persis dokumen yang sama ini sebagai pra-simpan.

Harap beri tahu saya jika Anda memerlukan detail tambahan.

@crispen-smith Saya perlu beberapa klarifikasi, ada terlalu banyak kode untuk saya pahami dengan mudah. Bisakah Anda mengaktifkan mode debug luwak dengan require('mongoose').set('debug', true); dan memposting hasilnya? Itu menunjukkan kepada saya pertanyaan dan tulisan yang sedang dikirim ke server.

Ya, itu banyak kode, tetapi pada saat yang sama ... tidak cukup untuk menjelaskannya dengan mudah.

Jadi, menjalankan debug sepertinya menyarankan bahwa save bahkan tidak terkena, inilah save dengan perubahan nama:

Mongoose: charts.findOne({ name: 'Chart With Measurements' }) { fields: undefined }  
Mongoose: charts.update({ _id: ObjectId("553da6c3d3d0940a640e878c"), __v: 3 }) { '$set': { 'sizes.0.name': 'Smaller' } } {} 

Berikut menjalankan urutan operasi yang sama dengan perubahan nama dan nilai dari array string:

Mongoose: charts.findOne({ name: 'Chart With Measurements' }) { fields: undefined }  
Mongoose: charts.update({ _id: ObjectId("553da6c3d3d0940a640e878c"), __v: 3 }) { '$set': { 'sizes.0.name': 'Small' } } {} 

Dan, hanya dengan perubahan ke variabel di dalam array:

Luwak: charts.findOne({ name: 'Chart With Measurements' }) { field: undefined }
(Yup, itu saja ... tidak ada permintaan pembaruan)

Saya akan mencoba untuk menambalnya dengan menghapus seluruh sub-dokumen setiap kali, setidaknya untuk saat ini... Saya tidak memerlukan integritas referensial atau id objek untuk tujuan khusus ini.

--MEMPERBARUI--
Saya sudah mencoba menghapus dan memuat ulang, tetapi sepertinya itu juga tidak berhasil. Meskipun saya tidak memiliki jejak keluaran untuk bagian ini, sepertinya penghapusan juga tidak memicu operasi back-end. Apakah ada semacam pemeriksaan kotor yang tidak dipicu?

Adakah opsi untuk membuka kembali ini mengingat catatan saya di atas?

@crispen-smith inilah upaya dasar saya untuk mereproduksi masalah sebagai skrip mandiri:

var mongoose = require('mongoose');
mongoose.set('debug', true);
var util = require('util');
var assert = require('assert');

mongoose.connect('mongodb://localhost:27017/gh1204');

var Schema = mongoose.Schema;

var measurement = new Schema({
    name: {type: String, required: true},
    instruction: {type: String, required: true}
});

var size = new Schema({
    name: {type: String, required: true},
    lengths: [String]
});

var chartSchema = new Schema({
    measurements: [measurement],
    sizes: [size]
});

var Chart = mongoose.model('gh1204', chartSchema);

Chart.create({}, function(error, chart) {
  assert.ifError(error);
  chart.sizes.push({ name: 'bacon', lengths: ['25'] });
  chart.save(function(error, chart) {
    assert.ifError(error);
    assert.equal(chart.sizes[0].lengths.length, 1);
    assert.equal(chart.sizes[0].lengths[0], '25');
    console.log('done');
    process.exit(0);
  });
});

Tidak ada dadu sejauh ini, itu berjalan seperti yang diharapkan. Bisakah Anda mengubah contoh di atas untuk menunjukkan masalah yang Anda lihat? Saya belum bisa menerjemahkan deskripsi prosa Anda ke dalam kode.

Tentu saja, saya akan melihat ini sedikit nanti malam.

Coba ini?

/*jslint node:true */
"use strict";

var mongoose = require('mongoose');
mongoose.set('debug', true);
var util = require('util');
var assert = require('assert');

mongoose.connect('mongodb://localhost:27017/gh1204');

var Schema = mongoose.Schema;

var measurement = new Schema({
  name: {type: String, required: true},
  instruction: {type: String, required: true}
  });

var size = new Schema({
  name: {type: String, required: true},
  lengths: [String]
    });

var chartSchema = new Schema({
  measurements: [measurement],
  sizes: [size]
    });

var Chart = mongoose.model('gh1204', chartSchema);

Chart.create({}, function (error, chart) {
    assert.ifError(error);
    chart.sizes.push({ name: 'bacon', lengths: ['25'] });
    chart.save(function (error, chart) {
      assert.ifError(error);
     assert.equal(chart.sizes[0].lengths.length, 1);
     assert.equal(chart.sizes[0].lengths[0], '25');
     console.log('Created Index');

    chart.sizes[0].lengths[0] = "20";

  chart.save(function (error, chart) {
    assert.ifError(error);
    assert.equal(chart.sizes[0].lengths.length, 1);
    assert.equal(chart.sizes[0].lengths[0], '25');
    console.log('Created Index');
    process.exit(0);

    });
  });
});

Inilah keluaran konsol saya di konsol simpul saya:

Crispens-MacBook-Pro:mongooseTest crispensmith$ node index.js
Mongoose: gh1204.insert({ _id: ObjectId("5580d0c44d32b07971dfd281"), sizes: [], measurements: [], __v: 0 })   
Mongoose: gh1204.update({ __v: 0, _id: ObjectId("5580d0c44d32b07971dfd281") }) { '$set': { measurements: [] }, '$pushAll': { sizes: [ { name: 'bacon', _id: ObjectId("5580d0c44d32b07971dfd282"), lengths: [ '25' ] } ] }, '$inc': { __v: 1 } }  
Created Index
Mongoose: gh1204.update({ __v: 1, _id: ObjectId("5580d0c44d32b07971dfd281") }) { '$set': { measurements: [] }, '$inc': { __v: 1 } }  

/Users/crispensmith/Documents/mongooseTest/node_modules/luwak/node_modules/mpromise/lib/promise.js:108
if (this.ended && !this.hasRejectListeners()) throw reason;
^
AssertionError: "20" == "25"
di EventEmitter.(/Users/crispensmith/Documents/mongooseTest/index.js:44:14)
di EventEmitter.(/Users/crispensmith/Documents/mongooseTest/node_modules/luwak/node_modules/mpromise/lib/promise.js:175:45)
di EventEmitter.emit (events.js:98:17)
di Promise.safeEmit (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_modules/mpromise/lib/promise.js:81:21)
di Promise.fulfill (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_modules/mpromise/lib/promise.js:94:24)
di Promise.resolve (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/lib/promise.js:113:23)
di model.(/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/lib/document.js:1569:39)
di next_ (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_modules/hooks-fixed/hooks.js:89:34)
di EventEmitter.fnWrapper (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_ modules/hooks-fixed/hooks.js:171:15)
di EventEmitter.(/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_ modules/mpromise/lib/promise.js:175:45)
di EventEmitter.emit (events.js:98:17)
di Promise.safeEmit (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_modules/mpromise/lib/promise.js:81:21)
di Promise.fulfill (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_modules/mpromise/lib/promise.js:94:24)
di p1.then.then.self.isNew (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/lib/model.js:254:27)
di newTickHandler (/Users/crispensmith/Documents/mongooseTest/node_modules/mongoose/node_modules/mpromise/lib/promise.js:229:18)
di process._tickCallback (node.js:442:13)

(maaf, telah menghabiskan banyak waktu untuk membuat ini menjadi penurunan harga yang tepat, ini adalah yang terbaik yang bisa saya lakukan.)
Dan inilah output mongoDB:

  > db.gh1204.find();
  { "_id" : ObjectId("5580d0c44d32b07971dfd281"), "sizes" : [ { "name" : "bacon", "_id" : ObjectId("5580d0c44d32b07971dfd282"), "lengths" : [ "25" ] } ], "measurements" : [ ], "__v" : 2 }

Dari perspektif CRUD, intinya adalah tidak ada masalah dengan Create atau Reads, put Updates gagal.

TLDR;
Dalam kasus penggunaan saya, ini berarti bahwa setelah satu set panjang telah ditentukan untuk pengukuran, mereka tidak dapat diedit. Saya sedang mengerjakan proyek ritel fesyen dengan dua kasus penggunaan yang membutuhkan array di dalam sub-dokumen. Kasus penggunaan pertama adalah bahwa pengguna vanilla akan memiliki profil mereka sendiri, dan harus dapat mempertahankannya. Kasus penggunaan kedua adalah bahwa peran admin dapat membuat bagan khusus untuk daftar untuk berbagai jenis produk (atas, bawah, dll.). Saya biasanya tidak mengharapkan profil admin perlu mengedit bagan sekunder ini tetapi masih bagus untuk memiliki kasus penggunaan itu.

Secara teori, fungsi saat ini sebenarnya menyajikan objek yang bagus (tidak disengaja), tetapi jumlah pekerjaan yang terlibat dalam menggunakannya sebagai objek yang tidak dapat diubah daripada hanya pengeditan tidak sepele.

Saya melihat apa masalahnya - kasus klasik dari pertanyaan pertama di FAQ luwak . Mongoose tidak dapat melacak perubahan ketika Anda menetapkan indeks array secara langsung tanpa sesuatu seperti ES6 proxy atau ES7 Object.observe() . Menggunakan

chart.sizes[0].lengths.set(0, "20");

atau

chart.sizes[0].lengths[0] = '20';
chart.markModified('sizes.0.lengths.0');

Oke, itu masuk akal. Anehnya, (dan ini mungkin dikaitkan dengan strategi pencarian saya) saya hanya dapat menemukan fungsi yang beroperasi 1x per penyimpanan, dan tidak ada yang sesuai dengan kasus penggunaan.

Saya melihat apa masalahnya - kasus klasik dari pertanyaan pertama di FAQ luwak.

Terima kasih, itu masalah ini dalam kasus saya! :)

model.myArray[index] = anyValue

menjadi

model.myArray.set(index, anyValue)

Ini juga menjadi masalah bagi saya, saya berharap saya melihat utas ini lebih cepat!

Jika Anda tidak yakin luwak mendapatkan pemberitahuan tentang perubahan, Anda dapat menggunakan

doc.markModified('propChanged')
doc.save() // works

Saya telah memecahkan masalah saya dengan Array.set() juga.
:+1:

Mendapat kesalahan yang sama, ini adalah cuplikan kode saya
image
Dan ini adalah log luwak
image
Ini yang saya dapat dari tukang pos
image

Ada yang salah?

++ EDIT ++

  1. Mencoba menggunakan Array.set, dapatkan hasil yang sama

Saya pikir pertanyaan yang lebih baik adalah apakah ada sesuatu yang benar. Anda melakukan penyimpanan asinkron di blok if (req.body.invite != []) dan kemudian memodifikasi larik invited dalam panggilan balik penyelesaian. Panggilan nRoom.invited.push() akan selalu terjadi setelah panggilan save() ke-2. Juga, req.body.invite != [] akan selalu benar karena [] == [] salah di JS.

@vkarpov15 Haha Oke, terima kasih atas jawabannya! 👍 Banyak hal yang harus dipelajari :)

@peterkrieg Terima kasih!

Hai, saya mengalami masalah ini saat memperbarui dokumen yang disematkan, apakah ada yang punya saran? Kode saya ada di:

https://stackoverflow.com/questions/51426326/updating-deeply-embedded-documents-with-mongodb-2-6-12

@thehme kamu pake luwak versi berapa?

pada baris ini, {$set: {["dT." + index +".ts." + i + ".th"]: newValue}} , tanda kurung siku terasa tidak pada tempatnya bagi saya. apakah ada bedanya menggunakan {$set: { "dT." + index +".ts." + i + ".th": newValue } } sebagai gantinya?

$set docs hanya menampilkan string

jangan ragu untuk bergabung dengan kami di Gitter.im atau Slack untuk membicarakannya secara langsung 👍

Saya menggunakan 5.5.11 dan masih mengalami masalah ini. Saya sudah mencoba semua solusi yang diusulkan di utas ini tanpa hasil. Tata letak dokumen saya terlihat seperti ini:

{
  myObj: {
    myArr: [{ key: "value" }]
  }
}

myDoc.myObj.myArr.push({ key: "value2" });
// debugging myDoc shows new embedded doc
await myDoc.save();
// console shows new embedded doc is gone

Sunting: Ditingkatkan ke terbaru (5.7.6) dan masih mengalami masalah.

Skrip di bawah ini berfungsi dengan baik di Mongoose 5.7.6. Silakan buka edisi baru dan ikuti template edisi.

const mongoose = require('mongoose');

run().catch(err => console.log(err));

async function run() {
  await mongoose.connect('mongodb://localhost:27017/test', {
    useNewUrlParser: true,
    useUnifiedTopology: true
  });
  await mongoose.connection.dropDatabase();

  const schema = mongoose.Schema({ 
    myObj: { myArr: [{ key: String }] }
  });
  const Model = mongoose.model('Test', schema);


  await Model.create({ myObj: { myArr: [{ key: 'value' }] } });
  const myDoc = await Model.findOne();

  myDoc.myObj.myArr.push({ key: "value2" });
  await myDoc.save();

  console.log(myDoc.myObj.myArr);

  const saved = await Model.findOne();
  console.log(myDoc.myObj.myArr);
}
Apakah halaman ini membantu?
0 / 5 - 0 peringkat