[英]Mongoose findOneAndUpdate: create and then update nested array
我有一個程序,用於從服務器請求天氣數據,處理數據,然后使用貓鼬將其保存到mlab帳戶。 我正在收集10年的數據,但是我從中請求數據的API一次只能允許大約一年的時間。
我正在使用findOndAndUpdate為每個氣象站創建/更新文檔,但是在更新數據對象內的數組時遇到了麻煩。 (可能不是描述它的最佳方式...)
例如,下面是模型:
const stnDataSchema = new Schema(
{
station: { type: String, default: null },
elevation: { type: String, default: null },
timeZone: { type: String, default: null },
dates: {},
data: {}
},
{ collection: 'stndata' },
{ runSettersOnQuery: true }
)
date對象看起來像這樣:
dates: ["2007-01-01",
"2007-01-02",
"2007-01-03",
"2007-01-04",
"2007-01-05",
"2007-01-06",
"2007-01-07",
"2007-01-08",
"2007-01-09"]
和這樣的數據對象:
"data": [
{
"maxT": [
0,
null,
4.4,
0,
-2.7,
etc.....
我想要發生的是,當我運行findOneAndUpdate時,我想根據工作站查找文檔,然后將新的maxT值和日期附加到相應的數組中。 我有它為日期數組工作,但由於我要更新的元素是嵌套的,所以數據數組遇到麻煩。 我嘗試了這個:
const update = {
$set: {'station': station, 'elevation': elevation, 'timeZone': timeZone},
$push: {'dates': datesTest, 'data.0.maxT': testMaxT}};
StnData.findOneAndUpdate( query, update, {upsert: true} ,
function(err, doc) {
if (err) {
console.log("error in updateStation", err)
throw new Error('error in updateStation')
}
else {
console.log('saved')
但是這樣輸出到mlab:
"data": {
"0": {
"maxT": [
"a",
"b",
問題是我得到的是“ 0”而不是一個元素的數組。 我嘗試了“ data [0] .maxT”,但是這樣做沒有任何反應。
問題是,第一次運行工作站數據時,我想在第三個代碼塊中創建一個格式為data對象的新文檔,然后在后續運行中,一旦該文檔已存在,請更新maxT數組具有新的價值。 有任何想法嗎?
您將得到以下輸出:
"data": {
"0": {
"maxT": [
"a",
"b",
因為您正在整理文檔。 處理文檔數組時,上裝會變得有些復雜。
更新數組時,MongoDB知道data.0
指向數組中的第一個元素。 但是,在插入時,MongoDB不能確定它是數組還是對象。 因此,它假定它是一個對象。 因此,它不會插入["val"]
,而是插入{"0": "val"}
。
最簡單的解決方案
不要使用upsert。 為每個新氣象站插入一個文檔,然后使用findOndAndUpdate
將值推入文檔中的數組。 只要您第一次正確插入數組,就可以將它們壓入它們而不會變成對象。
如果data
僅包含一個對象,則為另一種簡單解決方案
從您的問題來看,您似乎在data
只有一個對象。 如果是這種情況,您可以將maxT
數組maxT
頂級,而不是成為數組中單個文檔的屬性。 然后它就像dates
一樣。
更復雜的MongoDB 3.6解決方案
如果您真的不能沒有upserts,MongoDB 3.6就會引入過濾后的位置運算符$[<identifier>]
。 您可以使用此運算符來更新與查詢匹配的數組中的特定元素。 與簡單的位置運算符$
,只要使用精確匹配,新的$[<identifier>]
運算符就可以用於補高。
您可以在此處了解有關此運算符的更多信息: https : //docs.mongodb.com/manual/reference/operator/update/positional-filtered/
因此,您的data
對象將需要具有一個可以完全匹配的字段(例如name
)。 查詢示例如下所示:
let query = {
_id: 'idOfDocument',
data: [{name: 'subobjectName'}] // Need this for an exact match
}
let update = {$push: {'data.$[el].maxT': testMaxT}}
let options = {upsert: true, arrayFilters: [{'el.name': 'subobjectName'}]}
StnData.findOneAndUpdate(query, update, options, callbackFn)
如您所見,這增加了更多的復雜性。 忘記嘗試進行增補會容易得多。 只需插入一個然后更新。
而且,mLab當前不支持MongoDB 3.6。 因此,只有在支持3.6之前,使用mLab時該方法才可行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.