Mongoose: Array kosong disimpan ketika properti mereferensikan skema

Dibuat pada 6 Feb 2013  ·  39Komentar  ·  Sumber: Automattic/mongoose

var FooSchema = new Schema({});
var Foo = mongoose.model("Foo", FooSchema);
var BarSchema = new Schema({
    foos: [Foo.schema]
});
var Bar = mongoose.model("Bar", BarSchema);

var b = new Bar();
b.save();

Itu akan membuat array kosong b.foos alih-alih membiarkan properti tidak terdefinisi.

enhancement

Komentar yang paling membantu

@antonioaltamura saya lupa tentang masalah ini, di bawah ini berfungsi di luwak 4.6:

const CollectionSchema = new Schema({
 field1: { type: [String], default: void 0 }, // <-- override the array default to be undefined
});

const Collection = mongoose.model('test', CollectionSchema);

Collection.create({}).
  then(doc => { console.log(doc); return doc; }).
  then(() => { process.exit(0); });

Semua 39 komentar

Ini adalah dengan desain. Semua nilai default disimpan sehingga tampilan aplikasi luwak dari dokumen identik dengan tampilan aplikasi non luwak.

Ok, bagaimana cara membuat nol default? ;-) Kasus penggunaan di sini adalah mahal di mongo untuk meminta semua Bar yang memiliki foos kosong. Saya harus menambahkan properti lain untuk melacak keadaan itu, yang semakin memperumit kode saya.

Jadi begitu. Ini akan membiarkan Anda melewatkan menyimpan foos kosong di dokumen baru:

BarSchema.pre('save', function (next) {
  if (this.isNew && 0 === this.foos.length) {
    this.foos = undefined;                                                                                                                                   
  }
  next();
})

Manis. Itu pekerjaan yang cukup baik bagi saya.

Apakah solusi ini masih berfungsi? (luwak 3.8.3 di sini)

Mathieumg: itu tidak berhasil untuk saya (3.8.15)

Ya, saya pikir masalah ini patut mendapat perhatian. (Ini cukup kecil, tapi
Saya tertarik menggunakan pre untuk hal-hal lain :))

Pada Senin, 25 Agustus 2014 pukul 16:49, Mathieu M-Gosselin <
[email protected]> menulis:

Mungkin saya harus membuka masalah baru agar ini diperhatikan?


Balas email ini secara langsung atau lihat di GitHub
https://github.com/LearnBoost/mongoose/issues/1335#issuecomment -53328195
.

+1
Pekerjaan awal tidak berfungsi untuk 3.8.15
satu-satunya alternatif yang saya pikir adalah memiliki null atau false untuk menyederhanakan kueri tetapi itu juga menambahkan beberapa byte dan memiliki efek signifikan pada basis data besar.

        this.foos = null;

@gaurang171 @Nepoxx dapatkah Anda memberi saya beberapa kode yang mereproduksi ini? Solusinya berfungsi dengan baik dalam kasus pengujian kami (lihat kasus uji )

Ini masih menjadi masalah bagi saya menggunakan 4.0.1.

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var barSchema = new mongoose.Schema({
  baz: String
});

var fooSchema = new mongoose.Schema({
  bars: [barSchema]
});

var Foo = mongoose.model('Foo', fooSchema);

var foo = new Foo();
console.log(foo); // { _id: 55256e20e3c38434687034fb, bars: [] }

foo.save(function(err, foo2) {
  console.log(foo2); // { __v: 0, _id: 55256e20e3c38434687034fb, bars: [] }

  foo2.bars = undefined;
  foo2.save(function(err, foo3) {
    console.log(foo3); // { __v: 0, _id: 55256e20e3c38434687034fb, bars: undefined }

    Foo.findOne({ _id: foo3._id }, function(err, foo4) {
      console.log(foo4); // { _id: 55256e20e3c38434687034fb, __v: 0, bars: [] }

      mongoose.disconnect();
    });
  });
});

@viking Itu tidak pernah 'diperbaiki'. Sebuah solusi diberikan . Anda harus menguji untuk melihat apakah solusi itu masih berfungsi karena ada informasi yang saling bertentangan tentang itu. =)

Saya sudah memiliki solusi. Saya tertarik untuk mengetahui apakah perilaku ini akan berubah atau tidak.

Maaf, Anda tidak mengatakan ingin tahu apakah perilakunya akan berubah atau tidak.

Saya sebenarnya tidak yakin mengapa masalah ini dibuka kembali oleh @vkarpov15 , yang

Ya perilaku ini tidak akan berubah dalam waktu dekat. Saya membuka kembali masalah ini jadi saya tahu untuk menyelidikinya ketika saya mendapat kesempatan, karena saya memastikan untuk memahami apa yang terjadi dengan setiap komentar yang masuk ke github luwak dan ini adalah salah satu yang saya tidak punya jawaban yang baik untuk dari atas kepalaku. Melihat lebih dekat, kami tidak dapat benar-benar mengubah ini dalam waktu dekat karena semver, tetapi sesuatu untuk diselidiki apakah itu titik sakit bagi banyak pengguna.

Saya telah menggunakan solusi ini dengan twist karena terkadang Anda INGIN menulis array kosong dan terkadang tidak.

Jadi Presave saya terlihat seperti ini:

        var schema = mongoose.Schema({
                   ...
           "children": [ String ]
                   ...
            });
        // turn off the saving of empty children if there are no children in the schema.
        schema.pre('save', function (next) {
            if (this.isNew) {
                if (this.children.length == 0) {
                    this.children = undefined;       
                }
                else if (this.children.length == 1 && this.children[0] == null) {
                    this.children = [];
                }                                                                                                                    
            }
            next();
        });
        var model = mongoose.model('MyDocument', schema);

Dan kemudian untuk menulis anak-anak kosong saya menggunakan ini:

idea.children = [null];

Sedangkan ini dilucuti:

idea.children = [];

Ini mungkin tidak berhasil untuk Anda, tetapi Anda harus dapat menemukan beberapa jenis skema lain.

Ini adalah masalah yang cukup besar ketika Anda memiliki array di dalam objek bersarang.

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var quxSchema = new mongoose.Schema({ qux: String });
var fooSchema = new mongoose.Schema({ foo: { bar: { baz: [ quxSchema ] } } });
var Foo = mongoose.model('Foo', fooSchema);

var foo = new Foo({foo: undefined})
foo.save(function(err, foo) {
  console.log(JSON.stringify(foo)); // {"__v":0,"_id":"557ae56480f047fd4ff4ab26","foo":{"bar":{"baz":[]}}}
  Foo.find({ _id: foo._id }, function(err, foos) {
    console.log(JSON.stringify(foos[0])); // {"_id":"557ae56480f047fd4ff4ab26","__v":0,"foo":{"bar":{"baz":[]}}}
  });
});

Di sini saya berharap foo hilang, dan sebagai gantinya saya memiliki objek bersarang ini dengan array kosong.

Tapi tidak bisakah pra-penyimpanan membantu Anda di sini? daripada memiliki {foo: undefined} Anda bisa menggunakan tipe unik foo untuk menandakan null foo, dan kemudian menghapus foo di presave.

Jelek sekalipun.

Saya baru saja mengalami masalah yang sama seperti yang dilakukan @viking . apakah Anda menemukan solusi yang bisa digunakan?

saya mencobanya dengan cara penyimpanan 'pra' .. tetapi kadang-kadang masih terjadi, saya tidak yakin berapa banyak kasus penggunaan berbeda yang harus saya bahas untuk menyelesaikannya. Masalah terbesar saya dari ini adalah bahwa JSON harus benar-benar mengirimkan objek, dan bukan array. ini adalah pengecualian fatal untuk parser json saya yang mencoba memetakan hal-hal ini ke objek Java.

contoh:

var subA = mongoose.Schema({
     name: String,
     a: String
});

var subB = mongoose.Schema({
     name: String,
     b: String
});

var A = mongoose.Schema({
name: String,
filter: {
        lastupdate  : { type: Date, default: Date.now },
        subA: [{type: Schema.Types.ObjectId, ref: 'subA', unique: true}],
        subB: [{type: Schema.Types.ObjectId, ref: 'subB', unique: true}]
    }
});

var ModelA = mongoose.model('A', A);

var obj = new modelA();
obj.save();

... ini menghasilkan:

{
 filter: []
}

tetapi seharusnya tidak ada di sana, atau setidaknya menjadi objek dan bukan array kosong:

{
 filter: {} 
}

seseorang ide bagaimana untuk memecahkan ini?

Salam

Saya pikir Anda dapat membuat ini berfungsi, jelas tidak dengan presave yang saya posting, karena itu melibatkan anak-anak menjadi array bukan objek. Saya belum mencoba ini, tetapi apakah mungkin untuk benar-benar menggunakan objek kosong "mengetik bebek" untuk menandakan objek kosong SEBENARNYA?

Jadi presave Anda mungkin:

if (this.isNew) {
    if (typeof(this.filter.empty) != "undefined") {
        this.filter = {};
    }
}

Kemudian untuk membuat filter kosong yang sebenarnya, Anda dapat menggunakan:

var obj = new modelA();
obj.filter = { empty: true };
obj.save();

Perhatikan bahwa sebenarnya tidak masalah jika skema tidak memiliki "kosong" di dalamnya, itu tidak pernah membuatnya menjadi luwak.

Entah bagaimana saya berhasil mengatasi masalah tersebut .. Saya sebenarnya melakukan sesuatu yang sangat mirip. Baru saja melihat jawaban Anda dan ingin mengucapkan terima kasih :)

Salam
Simon

Saya mengalami banyak masalah dengan solusi ini ketika ada skema bersarang dengan bidang Array opsional. Saya memecahkan ini dengan membuat tipe baru:

optional_array = 
  type: Mixed
  validate: 
    validator: (v) ->
      return v instanceof Array
    message: '{VALUE} needs to be an array.'

dan kemudian mengatur semua bidang saya ke optional_array alih-alih Array .

@simllll saya menggunakan null placeholder untuk objek yang hilang dan kemudian menghapus null sebelum menggunakan objek.

Maaf, tapi ini desain yang mengerikan. Anda tidak boleh memutuskan atas nama saya apakah saya ingin itu menjadi array kosong atau tidak disetel sama sekali. Setidaknya berikan opsi untuk menonaktifkan fitur ini.

Setuju dengan @ifeltsweet

Setelah berbulan-bulan, adakah solusi yang tepat tanpa pre hook? Saya memiliki lusinan bidang array, saya harus menangani satu per satu di pra kait ...

@antonioaltamura saya lupa tentang masalah ini, di bawah ini berfungsi di luwak 4.6:

const CollectionSchema = new Schema({
 field1: { type: [String], default: void 0 }, // <-- override the array default to be undefined
});

const Collection = mongoose.model('test', CollectionSchema);

Collection.create({}).
  then(doc => { console.log(doc); return doc; }).
  then(() => { process.exit(0); });

@vkarpov15 perbaikan Anda tidak berfungsi untuk saya di luwak 4.7.0. Masih bekerja baik-baik saja untuk Anda? Itu tidak termasuk nilai pada pembuatan objek baru tetapi ketika saya melakukan Model.save ia mencoba menambahkannya lagi.

@cpup22 dapatkah Anda memberikan contoh kode? Skrip yang direferensikan berfungsi dengan baik untuk saya di 4.7.1.

Saya pikir solusi dari https://github.com/Automattic/mongoose/issues/2363#issuecomment -171988413 jauh lebih bersih. Ini memungkinkan default ke null bahkan ketika default: null gagal:

const CollectionSchema = new Schema({
  field1: { type: [String] },
});
CollectionSchema.methods.postconstructed = function () {
  this.field1 = null;
};
CollectionSchema.queue('postconstructed');

const Collection = mongoose.model('test', CollectionSchema);

Collection.create({}).then(doc => { console.log(doc); process.exit(0) });

Tidak apa-apa, itu tidak berfungsi ketika meneruskan nilai (misalnya, new Collection({ field1: [] }) mendapat field1 === null . Jika saja ada kait konstruksi yang terjadi sebelum data yang diteruskan diterapkan dan setelah default array kosong dibuat. Atau bug ini diperbaiki untuk mengizinkan default: null untuk array.

Oh, sepertinya ini berhasil:

const CollectionSchema = new Schema({
  field1: { type: [String], default: () => null },
});

Jenis array lebih menghormati fungsi daripada nilai. Ini tidak memiliki masalah dengan menimpa null , [] diteruskan, atau nilai array yang tidak kosong melalui Collection.create() atau new Collection() .

@vkarpov15 halo, jadi bahkan jika saya mengubah nilai kunci untuk tipe array ke null dalam skema luwak saya sebelum mongo db menyimpan dokumen, dan ketika array kosong disimpan sebagai key = null.
Anda punya solusi?

@vikramkalta tolong berikan contoh kode, konversi prosa ke kode rawan kesalahan.

Hai, saya menggunakan luwak 4.6.5 dan masih menyimpan array kosong dengan solusi ini.

services: [{ type: Schema.Types.ObjectId, ref: 'Service', default: () => null }],

services: [{ type: Schema.Types.ObjectId, ref: 'Service', default: void 0 }],

@keyboard99 silakan ikuti petunjuk di https://github.com/Automattic/mongoose/issues/1335#issuecomment -252129243 . kode Anda menetapkan default untuk elemen array individual, bukan untuk array itu sendiri

Ada solusi sederhana untuk masalah itu. Cukup berikan nilai default sebagai tidak terdefinisi. Sebagai berikut:

var BarSchema = new Schema({
    foos: {
        type: [FooSchema],
        default: undefined
    }
});

Bekerja untuk saya

Tapi itu akan menyebabkan komplikasi dengan array.push
:(

@GeneralG ada komplikasi selain yang jelas harus dilakukan doc.array = doc.array || []; sebelum menelepon push() ?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat