mongooseを介して項目をmongo配列にプッシュする


185

私は答えを探してSOを精査しましたが、自分が何を求めているのかを説明するための適切な言葉を見つけられなかったと確信しています。

基本的に私は 'people'という名前のmongodbコレクションを持っています。そのコレクションのスキーマは次のとおりです。

people: {
         name: String, 
         friends: [{firstName: String, lastName: String}]
        }

これで、データベースに接続し、空の友達配列を持つ「人」を正常に作成する、非常に基本的な高速アプリケーションがあります。

アプリケーションの2番目の場所には、友達を追加するためのフォームが用意されています。フォームはfirstNameとlastNameを取り込んでから、適切なピープルオブジェクトを参照するために名前フィールドを含むPOSTを受け取ります。

私が苦労しているのは、新しいフレンドオブジェクトを作成して、それをフレンド配列に「プッシュ」することです。

mongo consoleを使用してこれを行う場合、ルックアップ基準の後に2番目の引数として$ pushを指定してupdate関数を使用しますが、mongooseにこれを行う適切な方法を見つけることができないようです。

db.people.update({name: "John"}, {$push: {friends: {firstName: "Harry", lastName: "Potter"}}});

更新: それで、エイドリアンの答えは非常に役に立ちました。以下は私の目標を達成するために私がしたことです。

私のapp.jsファイルで、私はを使用して一時的なルートを設定しました

app.get('/addfriend', users.addFriend);

私のusers.jsファイルのどこに

exports.addFriend = function (req, res, next)
{
var friend = {"firstName": req.body.fName, "lastName": req.body.lName};
Users.findOneAndUpdate({name: req.user.name}, {$push: {friends: friend}});
};

collections.findOneAndUpdate()を使用できる可能性があることはわかりますが、どこに実装するかわかりません。私のモデルでは?
Neurax

回答:


282

仮定すると、 var friend = { firstName: 'Harry', lastName: 'Potter' };

次の2つのオプションがあります。

メモリ内のモデルを更新し、保存します(プレーンのjavascript array.push):

person.friends.push(friend);
person.save(done);

または

PersonModel.update(
    { _id: person._id }, 
    { $push: { friends: friend } },
    done
);

mongooseがもたらす利点(フック、検証など)をより尊重するため、私は可能な限り常に最初のオプションを試してみます。

ただし、多数の同時書き込みを実行している場合は、競合状態に陥り、厄介なバージョンエラーが発生して、毎回モデル全体を置き換えたり、以前に追加したフレンドを失うことがなくなります。だから、絶対に必要なときだけ前者に行ってください。


1
2番目のオプションは、同時書き込み保護の点で実際には安全なオプションだと思いましたか?前者と言うつもりで、誤って後者と言ったのですか?
ブリックナー、

37
うん、私はちょうどチェックして(2017年11月に)、IS安全マングース使用しながら、機能を、それがされていない安全な、文書を見つけるために、メモリにそれを変更して、呼び出した文書のメソッドを。操作が「安全」であるとは、1つ、2つ、または50の変更がドキュメントに適用されている場合でも、それらはすべて正常に適用され、更新の動作が期待どおりであることを意味します。古くなったドキュメントで作業している可能性があるため、メモリ内での操作は本質的に安全ではなく、保存すると、フェッチ手順の後に発生した変更は失われます。update.save()
ブリクナー、

2
@Will Bricknerの一般的なワークフローは、ロジックを再試行ループでラップすることです(再試行にはフェッチ、変更、保存が含まれます)。VersionError(楽観的ロック例外)が返された場合、その操作を数回再試行して、毎回新しいコピーをフェッチできます。ただし、可能な限り、アトミック更新を優先します。
Adrian Schneider

8
@ZackOfAllTrades私も混乱しましたが、コールバック関数が完了したと思います。let done = function(err, result) { // this runs after the mongoose operation }
ユーザー

コールバックでフレンドオブジェクトのIDを取得する方法
Dee Nix

41

$プッシュオペレータは、配列に指定された値を追加します。

{ $push: { <field1>: <value1>, ... } }

$ pushは、値を要素とする配列フィールドを追加します。

上記の答えはすべての要件を満たしていますが、私は次のようにしてそれを機能させました

var objFriends = { fname:"fname",lname:"lname",surname:"surname" };
Friend.findOneAndUpdate(
   { _id: req.body.id }, 
   { $push: { friends: objFriends  } },
  function (error, success) {
        if (error) {
            console.log(error);
        } else {
            console.log(success);
        }
    });
)

これは私が機能することがわかったものです。これが2019年の時点で最新の状態だと思います。最良の答えは、何らかの形で欠けており、おそらく不完全/古くなっていることです。
Cheesus Toast

コードにわずかなエラーがある可能性があることを指摘しておきます。プロジェクトに適切な変数を設定したので、それが機能しました。Friend.findOneAndUpdate()がある場所は、People.findOneAndUpdate()になるはずです。それは、元の質問と一致しているでしょう。私はあなたのためにそれを編集することができますが、私が間違っている場合に備えて、あなたがそれを再確認することを望んでいます(私はノード/エクスプレスに少し新しいです)。
Cheesus Toast

@CheesusToast私が間違っているとしたら、答えを変えることができると思います。私はうまくいったこの答えを入れました。しかし、この答えが間違っているとわかった場合は、この答えを変更できます。あなたが私を訂正してくれれば嬉しいです:-)。
Parth Raval

1
わかりました。問題ありません。とにかく小さな編集でした。視聴者(私のように)がとにかくアレイがプッシュされている場所で問題を解決していたので、それは私にとってはちょっと気の毒なことです。私はまだこれが最良の答えになるはずだと思います:)
Cheesus Toast

10

$pushドキュメントを更新し、配列内に新しい値を挿入するために使用します。

見つける:

db.getCollection('noti').find({})

検索結果:

{
    "_id" : ObjectId("5bc061f05a4c0511a9252e88"),
    "count" : 1.0,
    "color" : "green",
    "icon" : "circle",
    "graph" : [ 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 2.0
        }
    ],
    "name" : "online visitor",
    "read" : false,
    "date" : ISODate("2018-10-12T08:57:20.853Z"),
    "__v" : 0.0
}

更新:

db.getCollection('noti').findOneAndUpdate(
   { _id: ObjectId("5bc061f05a4c0511a9252e88") }, 
   { $push: { 
             graph: {
               "date" : ISODate("2018-10-24T08:55:13.331Z"),
               "count" : 3.0
               }  
           } 
   })

更新の結果:

{
    "_id" : ObjectId("5bc061f05a4c0511a9252e88"),
    "count" : 1.0,
    "color" : "green",
    "icon" : "circle",
    "graph" : [ 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 2.0
        }, 
        {
            "date" : ISODate("2018-10-24T08:55:13.331Z"),
            "count" : 3.0
        }
    ],
    "name" : "online visitor",
    "read" : false,
    "date" : ISODate("2018-10-12T08:57:20.853Z"),
    "__v" : 0.0
}

2

これを行う簡単な方法は、以下を使用することです。

var John = people.findOne({name: "John"});
John.friends.push({firstName: "Harry", lastName: "Potter"});
John.save();

0

私の場合、私はこれをしました

  const eventId = event.id;
  User.findByIdAndUpdate(id, { $push: { createdEvents: eventId } }).exec();

-3

私もこの問題に遭遇しました。私の修正は、子スキーマを作成することでした。モデルの例については、以下を参照してください。

----人モデル

const mongoose = require('mongoose');
const SingleFriend = require('./SingleFriend');
const Schema   = mongoose.Schema;

const productSchema = new Schema({
  friends    : [SingleFriend.schema]
});

module.exports = mongoose.model('Person', personSchema);

***重要:SingleFriend.schema->スキーマには必ず小文字を使用してください

---子スキーマ

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

const SingleFriendSchema = new Schema({
  Name: String
});

module.exports = mongoose.model('SingleFriend', SingleFriendSchema);

おそらく、反対票の理由は、これが必要ではないと思われるためです。Parth Ravalの答えは十分です。
Cheesus Toast
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.