我有这个查询有效,但我希望doc只显示ü
而不是整个数组。如果我写network.stations.$
,我会收到错误。有没有办法让doc只返回fields: network.stations.$
中的单个元素?
[stations]
答案 0 :(得分:1)
答案是“是”,但不是你期望的方式。正如您在问题中所述,将network.stations.$
放入"fields"
选项以定位返回“已修改”文档会引发特定错误:
“不能使用位置投影并返回新文档”
然而,这应该是“提示”,因为当您知道要修改的值时,您并不真正“需要”“新文档”。那么简单的情况是不返回"new"
文档,而是返回它的“找到状态”,这是“在原子修改之前”,并且只是对你在语句中要求应用的返回数据进行相同的修改
作为一个小小的演示:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const testSchema = new Schema({},{ strict: false });
const Test = mongoose.model('Test', testSchema, 'collection');
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
await Test.remove();
await Test.insertMany([{ a: [{ b: 1 }, { b: 2 }] }]);
for ( let i of [1,2] ) {
let result = await Test.findOneAndUpdate(
{ "a.b": { "$gte": 2 } },
{ "$inc": { "a.$.b": 1 } },
{ "fields": { "a.$": 1 } }
).lean();
console.log('returned');
log(result);
result.a[0].b = result.a[0].b + 1;
console.log('modified');
log(result);
}
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})();
产生:
Mongoose: collection.remove({}, {})
Mongoose: collection.insertMany([ { __v: 0, a: [ { b: 1 }, { b: 2 } ], _id: 59af214b6fb3533d274928c9 } ])
Mongoose: collection.findAndModify({ 'a.b': { '$gte': 2 } }, [], { '$inc': { 'a.$.b': 1 } }, { new: false, upsert: false, fields: { 'a.$': 1 } })
returned
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 2
}
]
}
modified
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 3
}
]
}
Mongoose: collection.findAndModify({ 'a.b': { '$gte': 2 } }, [], { '$inc': { 'a.$.b': 1 } }, { new: false, upsert: false, fields: { 'a.$': 1 } })
returned
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 3
}
]
}
modified
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 4
}
]
}
所以我在循环中进行修改,以便您可以看到更新实际应用于服务器,因为下一次迭代会增加已经增加的值。
仅仅通过省略"new"
选项,你得到的是处于“匹配”状态的文档,然后在修改之前返回该文档状态是完全有效的。修改仍然发生。
这里你需要做的就是在代码中进行相同的修改。添加.lean()
会使这一点变得简单,并且它再次完全有效,因为您“知道您要求服务器执行的操作”。
这比单独的查询更好,因为“单独”文档可以通过修改和查询之间的不同更新进行修改,以仅返回投影匹配的字段。
并且它比返回“all”元素并稍后过滤更好,因为当你真正想要的只是“匹配元素”时,潜力可能是“非常大的数组”。当然这实际上是这样做的。
答案 1 :(得分:0)
尝试将fields
更改为projection
,然后使用您之前尝试过的network.stations.$
。
如果您的查询无效,那么这可能就足够了。如果它仍然不起作用,您可以尝试将第二个参数更改为显式$set
。
Network.findOneAndUpdate({
"network.stations.id": req.params.station_Id
}, {
"$set": {
"network.stations.$.free_bikes": req.body.free_bikes
}
}, {
new: true,
projection: "network.stations.$"
}, (err, doc) => console.log(doc))