Mongoose ile öğeleri mongo dizisine itin


185

Cevabı çok iyi araştırdım ama eminim peşindeyim anlatmak için doğru kelimeleri kaybettim.

Temelde 'insanlar' adında bir mongodb koleksiyonum var. Bu koleksiyonun şeması aşağıdaki gibidir:

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

Şimdi, veritabanına bağlanan ve başarıyla boş bir arkadaş dizisi ile 'insanlar' yaratan çok temel bir ekspres uygulama var.

Başvuruda ikincil bir yerde, arkadaş eklemek için bir form mevcuttur. Form, firstName, lastName ve ardından ad alanı içeren POST öğelerini de uygun people nesnesine başvurmak için alır.

Yapmakta zorlandığım şey yeni bir arkadaş nesnesi oluşturmak ve daha sonra bunu arkadaşlar dizisine "itmek".

Bunu mongo konsolu üzerinden yaptığımda arama kriterlerinden sonra ikinci argümanım olarak $ push ile güncelleme işlevini kullandığımı biliyorum, ancak bunu yapmak için mongoose almanın uygun yolunu bulamıyorum.

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

GÜNCELLEME: Yani, Adrian'ın cevabı çok yardımcı oldu. Amacımı gerçekleştirmek için yaptığım şey şu.

app.js dosyamda şunu kullanarak geçici bir rota belirledim:

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

users.js dosyamda nerede var

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

Potansiyel olarak collections.findOneAndUpdate () kullanabileceğimi görüyorum, ancak bunu nereye uygulayacağımdan emin değilim? Modelimde mi?
Neurax

Yanıtlar:


283

farz var friend = { firstName: 'Harry', lastName: 'Potter' };

İki seçeneğiniz vardır:

Modeli bellekte güncelleyin ve kaydedin (düz javascript array.push):

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

veya

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

Mümkün olduğunda her zaman ilk seçeneği denemeye çalışırım, çünkü mongoose'un size sağladığı faydalardan (kancalar, doğrulama vb.) Daha fazla saygı gösterecektir.

Ancak, çok sayıda eşzamanlı yazma işlemi yapıyorsanız, her seferinde tüm modeli değiştirmenizi ve eklediğiniz önceki arkadaşınızı kaybetmenizi önlemek için kötü sürüm hatalarıyla karşılaşacağınız yarış koşullarına çarpacaksınız. Bu yüzden öncekine sadece kesinlikle gerekli olduğunda gidin.


1
Ben ikinci seçenek aslında aynı anda yazma koruması açısından daha güvenli bir seçenek olduğunu düşündüm? Birincisi demek istediğinde yanlışlıkla ikincisini mi söyledin?
Brickner

37
Evet, ben sadece kontrol edilmiş ve (Kasım 2017 yılında), IS güvenli firavunfaresi kullanmak ise, fonksiyon o DEĞİLDİR güvenli bir belgeyi bulmak için bellekte değiştirmek ve sonra çağrı belge üzerinde yöntemini. Bir işlemin 'güvenli' olduğunu söylediğimde, bir belgeye bir, iki veya 50 değişiklik uygulansa bile, bunların hepsi başarıyla uygulanacak ve güncellemelerin davranışı beklediğiniz gibi olacaktır. Esasen bellek içi manipülasyon güvenli değildir, çünkü eski bir belge üzerinde çalışıyor olabilirsiniz, böylece kaydettiğinizde getirme adımından sonra meydana gelen değişiklikler kaybolur. update.save()
Brickner

2
@ Brickner, bunun için ortak bir iş akışı mantığınızı yeniden deneme döngüsüne sarmaktır: (yeniden denenebilir getirme, değiştirme, kaydetme içerir). Bir VersionError (iyimser kilit istisnası) geri alırsanız, bu işlemi birkaç kez yeniden deneyebilir ve her seferinde yeni bir kopya getirebilirsiniz. Yine de mümkünse atomik güncellemeleri tercih ediyorum!
Adrian Schneider

8
@ZackOfAllTrades Beni de karıştırdı, ama geri arama işlevi bittiğine inanıyorum. let done = function(err, result) { // this runs after the mongoose operation }
kullanıcı

geri aramada arkadaş nesnesinin kimliğini nasıl alabilirim?
Dee Nix

42

$ İtme operatörü bir diziye belirtilen değer ekler.

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

$ push , değer içeren dizi alanını öğesi olarak ekler.

Yukarıdaki yanıt tüm gereksinimleri karşılar, ancak aşağıdakileri yaparak işe koyuldum

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

Çalıştığım bulduğum bu, bu yüzden 2019'dan beri en güncel olanı. Sanırım en iyi cevap bu bir şekilde eksik ve belki de eksik / güncel değil.
Cheesus Tost

Kodda küçük bir hata olabileceğini gösterebilir miyim. Çalıştım çünkü projem için doğru değişkeni koydum. Friend.findOneAndUpdate () olduğu yerde People.findOneAndUpdate () olması gerektiğini düşünüyorum. Bu asıl soru ile daha uyumlu olacaktır. Senin için düzenleyebilirim ama yanlış olursam sadece çift kontrol etmeyi tercih ederim (düğüm / ekspres için biraz yeniyim).
Cheesus Tost

@CheesusToast Sanırım, eğer yanılıyorsam, cevabı değiştirebilirsiniz. benim için iyi çalışan bu cevabı koydum. ama bu cevabı yanlış bulursanız, bu cevabı değiştirebilirsiniz & beni düzeltirseniz sevinirim :-).
Parth Raval

1
Tamam, sorun değil, yine de sadece küçük bir düzenleme oldu. İzleyiciler (benim gibi) dizinin zaten itildiği yerde çalışmış olacaktı çünkü benim tür nit-seçici. Hala bunun en iyi cevap olması gerektiğini düşünüyorum :)
Cheesus Tost

Sadece başkalarının bunun mükemmel çalıştığını bilmelerini istedim, 2020 ve hala mükemmel çalışıyor. Ben sadece findByOd yerine findById kullandım, yine de yardım dostum için teşekkürler.
Mob_Abominator

10

$pushBelgeyi güncellemek ve bir diziye yeni değer eklemek için kullanın .

bulmak:

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

bulmak için sonuç:

{
    "_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
}

Güncelleme:

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

güncelleme sonucu:

{
    "_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

Bunu yapmanın kolay bir yolu aşağıdakileri kullanmaktır:

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

0

Benim durumumda bunu yaptım

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

-3

Ben de bu sorunla karşılaştım. Benim düzeltmem bir çocuk şeması oluşturmaktı. Modellerinize ilişkin bir örnek için aşağıya bakın.

---- Kişi modeli

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

*** Önemli: SingleFriend.schema -> şema için küçük harf kullandığınızdan emin olun

--- Çocuk şeması

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

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

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

Muhtemelen düşüşün sebebi bunun gerekli görünmemesidir. Parth Raval'ın cevabı oldukça yeterli.
Cheesus Tost
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.