此Meteor服务器端(Mongo 1.1.18)尝试根据所示的选择器插入文档,但出现以下错误:
myCol.upsert({name: 'sam', job: {$exists: false}}, {$set: {parents: ['jack', 'jacky']}});
MongoError:美元($)前缀字段' $存在'在' job。$ exists'对存储无效。
如何插入此选定文档?或者如果它不存在就创建它? THX
答案 0 :(得分:1)
原因是因为"upsert"
MongoDB正试图在新创建的对象中分配作为“值”提供的任何“查询”参数。由于您无法使用$
命名属性,因此它会尝试将字段“作业”创建为{ "job": { "$exists": true } }
,就像您在查询参数中提供的那样。
要避免这种情况,请通过指定$setOnInsert
告诉MongoDB在创建时实际使用哪些字段。至少对于普通的MongoDB集合来说就是这种情况。因此,对于“meteor”,您应该访问.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"
]
}