原因是因为"upsert" MongoDB 试图在新创建的对象中分配作为“值”提供的任何“查询”参数。由于您无法使用 $ 命名属性,因此会引发错误,因为它正在尝试将字段“job”创建为 { "job": { "$exists": true } },就像您在查询参数中提供的一样。
为避免这种情况,请通过指定 $setOnInsert 告诉 MongoDB 在创建时实际使用哪些字段。至少对于普通的 MongoDB 集合来说是这样。因此,对于“流星”,您应该访问 .rawCollection() 而不是“
myCol.rawCollection().update(
{name: 'sam', job: {$exists: false}},
{
$setOnInsert: { name: 'sam' },
$set: {parents: ['jack', 'jacky']}
},
{ upsert: true }
)
请注意,当您执行此操作时,不会使用其他各种流星默认值,例如 _id 的值,因此您可能需要使用替代方法。
这里的替代方法是改用 $where,它可以根据文档评估 JavaScript 条件以查看 "job" 字段不存在。即使从流星收集实现中,这实际上也不会被转移到“upsert”:
myCol.upsert(
{name: 'sam', '$where': "!this.hasOwnProperty('job')" },
{
$set: {parents: ['jack', 'jacky']}
}
)
为了证明这一点,我启动了一个纯流星项目,除了添加一个集合并在服务器启动时执行代码之外没有其他任何更改。所以基本上在一个新项目上更改server/main.js如下:
import { Meteor } from 'meteor/meteor';
import { People } from '../imports/people.js';
Meteor.startup(() => {
// code to run on server at startup
People.upsert(
{ name: 'john', '$where': "!this.hasOwnProperty('job')" },
{
'$set': { parents: [ 'jack', 'jacky' ] }
}
);
People.rawCollection().update(
{ name: 'bill', job: { '$exists': false } },
{
'$setOnInsert': { name: 'bill' },
'$set': { parents: [ 'jack', 'jacky' ] }
},
{ 'upsert': true }
)
});
还有imports/people.js:
import { Mongo } from 'meteor/mongo';
export const People = new Mongo.Collection('people');
并且文档按预期在集合中创建,没有错误:
{
"_id" : "irDWFLdACjNKYGEcN",
"name" : "john",
"parents" : [
"jack",
"jacky"
]
}
{
"_id" : ObjectId("596489d0902edee769372ac6"),
"name" : "bill",
"parents" : [
"jack",
"jacky"
]
}