MongoDB - Mongoose 查询 findOneAndUpdate() 不更新/复制数据库

Posted

技术标签:

【中文标题】MongoDB - Mongoose 查询 findOneAndUpdate() 不更新/复制数据库【英文标题】:MongoDB - Mongoose query findOneAndUpdate() doesn't update/duplicates the DB 【发布时间】:2019-04-19 04:41:47 【问题描述】:

我正在尝试保存和更新findOneAndUpdate()upsert: true - 如果对象不存在则创建对象)Web Api 的结果,其中包含用于填充股票图表的多个数据数组。每次我输入一个符号并单击“获取报价”按钮时,它应该从 web api 获取数据,在数据库的子模式下保存/更新它。如何使用 nodejs 和猫鼬做到这一点?这是我尝试过的代码......

文件夹 - 模型 - Stock.js

const mongoose = require('mongoose')
mongoose.Promise = global.Promise
mongoose.connect('mongodb://localhost:27017/myapp',  useNewUrlParser: true )
const slug = require('slug')


const childSchemaData = new mongoose.Schema(
  date: mongoose.Decimal128,
  open: mongoose.Decimal128,
  high: mongoose.Decimal128,
  low: mongoose.Decimal128,
  close: mongoose.Decimal128,
  volume: mongoose.Decimal128
)

const parentSchemaSymbol = new mongoose.Schema(
  symbol: 
    type: String,
    trim: true,
    minlength: 2,
    maxlength: 4,
    required: 'Plese enter a valid symbol, min 2 characters and max 4'
  ,
  // Array of subdocuments
  data: [childSchemaData],
  slug: String

);

//we have to PRE-save slug before save the parentSchemaSymbol into DB
parentSchemaSymbol.pre('save', function (next) 
  if (!this.isModified('symbol')) 
    next()//skip it
    return//stop this function from running
  
  this.slug = slug(this.symbol)
  next()
  //TODO make more resiliant soslug are unique
)

module.exports = mongoose.model('Stock', parentSchemaSymbol)

控制器 - webApiController.js

const mongoose = require('mongoose')
const axios = require('axios')

require('../models/Stock')
const parentSchemaSymbol = mongoose.model('Stock')



mongoose.Promise = global.Promise // Tell Mongoose to use ES6 promises
// Connect to our Database and handle any bad connections
mongoose.connect('mongodb://localhost:27017/myapp',  useNewUrlParser: true )
mongoose.connection.on('error', (err) => 
  console.error(`???? ???? ???? ???? ???? ???? ???? ???? → $err.message`)
)

exports.webApi = (req, res) => 
  let curValue = req.params.symbol

  axios.get(`https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=$curValue&outputsize=compact&apikey=TUVR`)
    .then(response => 
      return highLow = Object.keys(response.data['Time Series (Daily)']).map(date => 
        return 
          date: Date.parse(date),
          open: Math.round(parseFloat(response.data['Time Series (Daily)'][date]['1. open']) * 100) / 100,
          high: Math.round(parseFloat(response.data['Time Series (Daily)'][date]['2. high']) * 100) / 100,
          low: Math.round(parseFloat(response.data['Time Series (Daily)'][date]['3. low']) * 100) / 100,
          close: Math.round(parseFloat(response.data['Time Series (Daily)'][date]['4. close']) * 100) / 100,
          volume: parseInt(response.data['Time Series (Daily)'][date]['5. volume'])
        
      )

    )
    .then(_ => 

      let curValueSchema = new parentSchemaSymbol()

      curValueSchema.symbol = curValue
      highLow.map(item => 
        curValueSchema.data.push(item)
      )
      const query =  symbol: `$curValue.toUpperCase()` 
      const update =  $addToSet:  data: [curValueSchema.data]  
      const options =  upsert: true, new: true 
      curValueSchema.findOneAndUpdate(query, update, options).then(doc => 
        console.log('Saved the symbol', doc)
        return res.send(highLow)
      ).catch(e => 
        console.log(e)
      )
    )
    .catch(error => 
      console.log(error)
    )

这是我要修复的一段代码。其余工作正常:

 let curValueSchema = new parentSchemaSymbol()

      curValueSchema.symbol = curValue
      highLow.map(item => 
        curValueSchema.data.push(item)
      )
      const query =  symbol: `$curValue.toUpperCase()` 
      const update = curValueSchema
      const options =  upsert: true, new: true 
      curValueSchema.findOneAndUpdate(query, update, options).then(doc => 
        console.log('Saved the symbol', doc)
        return res.send(highLow)
      ).catch(e => 
        console.log(e)
      )

这是我遇到的错误

TypeError: curValueSchema.findOneAndUpdate is not a function
    at axios.get.then.then._ (/mnt/c/Users/john/Desktop/node/controllers/webApiController.js:55:22)
    at process._tickCallback (internal/process/next_tick.js:178:7)

这是数据 = highLow

解决方案

因为 Mongoose 默认创建一个新的 MongoDB ObjectId(这个隐藏的 _id 字段),每次你传递一个 javascript 对象来更新文档的字段。

您可以告诉 Mongoose 不要创建新的 ObjectId,方法是确保您的 mongoose 架构如下:

文件夹 - 模型 - Stock.js

const mongoose = require('mongoose')
mongoose.Promise = global.Promise
mongoose.connect('mongodb://localhost:27017/myapp',  useNewUrlParser: true )
const slug = require('slug')


const childSchemaData = new mongoose.Schema(
  "_id": false,
  date: mongoose.Decimal128,
  open: mongoose.Decimal128,
  high: mongoose.Decimal128,
  low: mongoose.Decimal128,
  close: mongoose.Decimal128,
  volume: mongoose.Decimal128
)

const parentSchemaSymbol = new mongoose.Schema(
  "_id": false,
  symbol: 
    type: String,
    trim: true,
    minlength: 2,
    maxlength: 4,
    required: 'Plese enter a valid symbol, min 2 characters and max 4'
  ,
  // Array of subdocuments
  data: [childSchemaData],
  slug: String

);

//we have to PRE-save slug before save the parentSchemaSymbol into DB
parentSchemaSymbol.pre('save', function (next) 
  if (!this.isModified('symbol')) 
    next()//skip it
    return//stop this function from running
  
  this.slug = slug(this.symbol)
  next()
  //TODO make more resiliant soslug are unique
)

module.exports = mongoose.model('Stock', parentSchemaSymbol)

控制器 - webApiController.js

let curValueSchema = new parentSchemaSymbol()

      curValueSchema.symbol = curValue
      highLow.map(item => 
        curValueSchema.data.push(item)
      )
      const query =  symbol: `$curValue.toUpperCase()` 
      const update = curValueSchema
      const options =  upsert: true, new: true 
      parentSchemaSymbol.findOneAndUpdate(query, update, options).then(doc => 
        console.log('Saved the symbol', doc)
        return res.send(highLow)
      ).catch(e => 
        console.log(e)
      )

【问题讨论】:

【参考方案1】:
    findOneAndUpdate 和 update 是一个模型方法,它可用于模型的实例,所以你得到方法未找到错误。

let curValueSchema = new parentSchemaSymbol()
curValueSchema.symbol = curValue
highLow.map(item = > 
  curValueSchema.data.push(item)
)
const query = 
  symbol: `$ 
    curValue.toUpperCase()
  `

const update = curValueSchema
const options = 
  upsert: true,
  new: true

parentSchemaSymbol.findOneAndUpdate(query, update, options).then(doc = > 
  console.log('Saved the symbol', doc)
  return res.send(highLow)
).
catch (e = > 
  console.log(e)
)

【讨论】:

啊哈,这很有道理。但出于同样的原因,它不能按预期工作。它正在插入重复值,pre('save') 不起作用。同样const query = symbol: `$curValue.toUpperCase()` 不适用toUpperCase() 为避免重复,我需要将"_id": false 添加到子架构和父架构中【参考方案2】:

这是一个模型的方法,而不是一个实例。 将实例名称替换为方案名称。

【讨论】:

啊哈,这很有道理。但出于同样的原因,它不能按预期工作。它正在插入重复值并且 pre('save') 不起作用。也 const query = symbol: $curValue.toUpperCase() 不适用于 toUpperCase() 为避免重复,我需要将"_id": false 添加到子架构和父架构中【参考方案3】:

代替:

curValueSchema.findOneAndUpdate

做:

parentSchemaSymbol.findOneAndUpdate

【讨论】:

啊哈,这很有道理。但出于同样的原因,它不能按预期工作。它正在插入重复值并且 pre('save') 不起作用。也 const query = symbol: $curValue.toUpperCase() 不适用于 toUpperCase() 为避免重复,我需要将"_id": false 添加到子架构和父架构中

以上是关于MongoDB - Mongoose 查询 findOneAndUpdate() 不更新/复制数据库的主要内容,如果未能解决你的问题,请参考以下文章

单链查询 mongodb / mongoose 获取所有评论

基于多个子文档的MongoDB/Mongoose查询

MongoDB(Mongoose)数据库查询问题

从两个数据库集合(Mongoose/MongoDB)中查询和匹配

Mongoose/mongoDB 查询加入.. 但我来自 sql 背景

Mongoose/mongoDB 查询加入.. 但我来自 sql 背景