Mongoose: プロパティがスキーマを参照すると、空の配列が保存されます

作成日 2013年02月06日  ·  39コメント  ·  ソース: 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();

これにより、プロパティを未定義のままにするのではなく、b.foosの空の配列が作成されます。

enhancement

最も参考になるコメント

@antonioaltamuraこの問題を忘れて

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); });

全てのコメント39件

これは仕様によるものです。 ドキュメントのマングースアプリケーションビューが非マングースアプリケーションビューと同じになるように、すべてのデフォルト値が保存されます。

わかりました。デフォルトをnullにするにはどうすればよいですか? ;-)ここでのユースケースは、空のfooを持つすべてのBarを要求するのにmongoでコストがかかることです。 その状態を追跡するために別のプロパティを追加する必要があります。これにより、コードがさらに複雑になります。

分かりました。 これにより、空のfooを新しいドキュメントに保存することをスキップできます。

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

甘い。 それは私にとって十分な回避策です。

この回避策はまだ機能するはずですか? (ここではmongoose 3.8.3)

Mathieumg:それは私には機能しません(3.8.15)

はい、この問題には注意が必要だと思います。 (それはかなりマイナーですが、
私は他のことにpreを使うことに興味があります:))

2014年8月25日月曜日午後4時49分、Mathieu M-Gosselin <
[email protected]>は次のように書いています:

おそらく、これに気付くために新しい問題を開く必要がありますか?


このメールに直接返信するか、GitHubで表示してください
https://github.com/LearnBoost/mongoose/issues/1335#issuecomment -53328195

+1
3.8.15では事前回避策が機能していません
私が考える唯一の選択肢は、クエリを単純化するためにnullまたはfalseを指定することですが、これによってバイトが追加され、大規模なデータベースに大きな影響を及ぼします。

        this.foos = null;

@ gaurang171 @Nepoxxは、これを再現するコードを私に提供できますか? この問題を回避するには、我々のテストケースで罰金に動作します(参照テストケースを

これは、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 「修正」されたことはありません。 回避策が提供されました。 それについて矛盾する情報があるので、その回避策がまだ機能するかどうかを確認するためにテストする必要があります。 =)

すでに回避策があります。 この振る舞いが変わるかどうか知りたいです。

申し訳ありませんが、動作が変わるかどうかを知りたいとは言わなかった。

この問題が@ vkarpov15によって再開された理由は実際には

ええ、この振る舞いは近い将来変わることはありません。 私はこの問題を再開したので、機会があれば調査することを知っていました。マングースのgithubに寄せられるすべてのコメントで何が起こっているのかを確実に理解しているためです。これは、良い答えがありませんでした。頭のてっぺんから。 もっと詳しく見てみると、semverのため、近い将来これを実際に変更することはできませんが、多くのユーザーにとって問題になるかどうかを調査する必要があります。

空の配列を書きたいときもあれば、書きたくないときもあるので、私はこの回避策をひねりを加えて使用しました。

したがって、私の事前保存は次のようになります。

        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);

そして、空の子を書くために私はこれを使います:

idea.children = [null];

これは取り除かれますが:

idea.children = [];

これはうまくいかないかもしれませんが、他のタイプのスキームを思い付くことができるはずです。

ネストされたオブジェクト内に配列がある場合、これはかなり大きな問題です。

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":[]}}}
  });
});

ここでは、 fooが欠落していると予想しますが、代わりに、空の配列を持つこのネストされたオブジェクトがあります。

しかし、事前保存はここであなたを助けることができませんか? {foo:undefined}を使用する代わりに、一意のタイプのfooを使用してnull fooを示し、事前保存でfooを削除することができます。

でも醜い。

@vikingと同じ問題が

'pre'保存方法で試してみましたが、それでも時々発生します。これを実行するためにカバーする必要のあるさまざまなユースケースの数がわかりません。 これからの私の最大の問題は、JSONが実際には配列ではなくオブジェクトを配信する必要があるということです。 これは、これらのものをJavaオブジェクトにマップしようとする私のjsonパーサーの致命的な例外です。

例:

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();

...これは次の結果になります:

{
 filter: []
}

ただし、そこに存在しないか、少なくともオブジェクトであり、空の配列ではない必要があります。

{
 filter: {} 
}

誰かがこれを解決する方法について何かアイデアはありますか?

よろしく

明らかに私が投稿したプリセーブではなく、この作業を行うことができると思います。これは、子がオブジェクトではなく配列であることが関係しているためです。 私はこれを試していませんが、実際に「ダックタイピング」の空のオブジェクトを使用して、実際の空のオブジェクトを示すことはできませんか?

したがって、事前保存は次のようになります。

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

次に、実際の空のフィルターを作成するには、次のものを使用できます。

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

スキーマに「空」が含まれていないかどうかは実際には問題ではないことに注意してください。マングースになることはありません。

どういうわけか私は問題を克服する方法を管理しました..私は実際に非常に似たようなことをしました。 ただあなたの答えを見て、ありがとうと言いたかったです:)

よろしく
サイモン

オプションのArrayフィールドを持つネストされたスキーマがある場合、このソリューションで多くの問題が発生していました。 私は新しいタイプを作成することでこれを解決しました:

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

その後、にすべての私のフィールドを設定するoptional_arrayの代わりにArray

@simllll不足しているオブジェクトにnullプレースホルダーを使用し、オブジェクトを使用する前にnull削除します。

申し訳ありませんが、これは恐ろしいデザインです。 空の配列にするか、まったく設定しないかを、私に代わって決定するべきではありません。 少なくとも、この機能を無効にするオプションを提供してください。

@ifeltsweetに同意する

数ヶ月後、プレフックなしの適切な解決策はありますか? 数十の配列フィールドがあるので、プリフックで1つずつ処理する必要があります...

@antonioaltamuraこの問題を忘れて

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あなたの修正は、マングース4.7.0では機能しません。 まだ大丈夫ですか? 新しいオブジェクト作成の値は含まれていませんが、Model.saveを実行すると、再度追加しようとします。

@ cpup22コードサンプルを提供できますか? 参照されているスクリプトは、4.7.1で正常に機能します。

https://github.com/Automattic/mongoose/issues/2363#issuecomment-171988413からの回避策ははるかにクリーンだと思います。 default: nullが失敗した場合でも、デフォルトでnull default: nullできます。

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) });

気にしないでください。値を渡すときは機能しません(たとえば、 new Collection({ field1: [] })field1 === null取得します。渡されたデータが適用される前とデフォルトの後に発生した構築フックがあった場合のみ空の配列が作成されます。または、このバグが修正され、配列にdefault: nullが許可されるようになりました。

ああ、これはうまくいくように見えます:

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

配列型のものは、値よりも関数を真摯に尊重します。 これは、渡されたnull[] 、またはCollection.create()またはnew Collection()介した空でない配列値の上書きに問題はありません。

@ vkarpov15こんにちは、mongo dbがドキュメントを保存する前に
解決策はありますか

@vikramkaltaはコードサンプルを提供してください。散文からコードへの変換はエラーが発生しやすいです。

こんにちは、私はマングース4.6.5を使用していますが、これらのソリューションで空の配列を保存しています。

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

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

その問題には簡単な解決策があります。 デフォルト値を未定義として指定するだけです。 次のように:

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

私のために働く

しかし、それはarray.pushの問題を引き起こします
:(

@GeneralG push()呼び出す前にdoc.array = doc.array || [];を実行しなければならないという明らかな問題以外の問題はありますか?

このページは役に立ちましたか?
0 / 5 - 0 評価