Mongoose一次插入多个相关记录

时间:2018-05-18 01:34:08

标签: node.js mongodb mongoose

目前我有以下内容,每次有效插入一首歌词:

ev.dataTransfer.files

但是我想将此更新为以下内容,我在一个数组中一次传递多个歌词...

function dropHandler(ev) {
    isDragged = true;
    ev.preventDefault();    

    formData = new FormData($("#form"));

    if (ev.dataTransfer.items) {
        // Use DataTransferItemList interface to access the file(s)
        for (var i = 0; i < ev.dataTransfer.items.length; i++) {
            // If dropped items aren't files, reject them
            if (ev.dataTransfer.items[i].kind === 'file') {
                var file = ev.dataTransfer.items[i].getAsFile();
                formData.append("File.PayLoad" + i, file);
            }
        }
    } else {
        // Use DataTransfer interface to access the file(s)
        for (var i = 0; i < ev.dataTransfer.files.length; i++) {
            file = ev.dataTransfer.files[i];
            formData.append("File.PayLoad" + i, file);
        }
    }
}

是否可以一次插入所有歌词并仍然将更新的歌曲返回到graphql

2 个答案:

答案 0 :(得分:1)

公平点。而不是findById()那么它可能更好地使用findByIdAndUpdate(),而且还可以创建内联和&#34;链&#34;而承诺:

SongSchema.statics.addLyrics = function(songId, lyrics) {
  const Lyric = mongoose.model('lyric');

  return Lyric.insertMany(lyrics).then( lyrics =>
    this.findByIdAndUpdate(
      songId,
     { "$push": { "lyrics": { "$each": lyrics } } },
     { "new": true }
  );
};

使用$each作为$push的修饰符,它接受和数组并执行&#34; atomic&#34;更新文档的操作。它比获取文档更有效,更安全。然后&#34;在更新之前修改它。

当然insertMany()你的阵列也是{#3}}。 lyrics作为单一写作而不是&#34;许多&#34;。

另一种方法是根据Array.map()save()并行创建实例。

SongSchema.statics.addLyrics = function(songId, lyrics) {
  const Lyric = mongoose.model('lyric');

  lyrics = lyrics.map(lyric => new Lyric(lyric));

  return Promise.all([
    this.findByIdAndUpdate(
      songId,
      { "$push": { "lyrics": { "$each": lyrics } } },
      { "new": true }
    ),
    ...lyrics.map(lyric => lyric.save())
  ]).then(([song, ...lyrics]) => song);
};

但是第一种方法确实具有较少的开销,Promise.all()不会响应直到&#34;所有&#34;无论如何,承诺得到了解决。因此,如果不进行系列操作,你真的无法获得任何收益。

另一种情况当然是代替保持&#34;数组&#34;在ObjectId中相关的Song值,您只需在songId条目中记录Lyric

因此,架构将变为:

const lyricSchema = new Schema({
  title: String,
  content: String,
  songId: { type: Schema.Types.ObjectId, ref: 'Song' }
})

然后插入就是

lyricSchema.statics.addLyrics = function(songId, lyrics) {
  return this.insertMany(lyrics.map(lyric => ({ ...lyric, songId })))
}

Song架构中,不是像这样保留数组:

songs: [{ type: Schema.Types.ObjectId, ref: 'Lyric' }]

删除它并替换为virtual

SongSchema.virtual.('songs', {
  ref: 'Lyric',
  localField: '_id',
  foreignField: 'songId'
});

这意味着根本不需要触摸Song模型,因为您只需插入相关数据而无需更新数组。

现代MongoDB版本确实应该使用$lookup来&#34;查询&#34;无论如何这个信息,以及&#34;阵列的维护&#34;在父母中是一种反模式&#34;通常应该避免。

&#34;虚拟&#34;因此&#34;是可选的&#34;,只是为了方便而启用populate()的方法。

答案 1 :(得分:0)

我所知道的最好的方式是这样的:

lyrics = lyrics.map((lyric. i) => {lyric, songId: songI[i]});

SongSchema.collection.insertMany(lyrics, {'ordered': false},
(err, data) => {
    /*Do your stuff*/
});

如果有任何重复的唯一值,则序列为true将抛出错误并停止,如果为false,则仍会抛出错误,但插入将继续执行非重复的值。 您不需要创建新的Schema,但这样也会跳过Momgoose验证。