given data
db.dummy.insert([{"prices":{"id":"a","ops":[{"id":"a1"},{"id":"a2"}]}},{"prices":{"id":"b","ops":[{"id":"b2"},{"id":"a1"}]}},{"prices":[{"id":"c","ops":[]}]}])```
/*
{ ..."prices" : { "id" : "a", "ops" : [ { "id" : "a1" }, { "id" : "a2" } ] } }
{ ..."prices" : { "id" : "b", "ops" : [ { "id" : "b2" }, { "id" : "a1" } ] } }
{ ..."prices" : [ { "id" : "c", "ops" : [ ] } ] }
*/
To fetch your document, you may apply your query:
priceId='a'
opsId='a1'
db.dummy.find({ 'prices.id': priceId, 'prices.ops.id': opsId })
/*
{ ..."prices" : { "id" : "a", "ops" : [ { "id" : "a1" }, { "id" : "a2" } ] } }
*/
To restrict the returned fields of the document, use a projection
In particular, the 'array.$' projection
query = { 'prices.id': priceId, 'prices.ops.id': opsId }
db.dummy.find(query, { 'prices.ops.$': 1 })
/*
{ "_id" : ObjectId("600d357fb9f5ffd060ed064e"), "prices" : { "ops" : [ { "id" : "a1" } ] } }
note: only the matching elem in ops is returned
*/
If you want to exclusively have the operation without having to care about traversing the tree (on js side), you may use an aggregate expr (from mongo 4.4)
db.dummy.find(query,{'addOp':{$filter: {input:'$prices.ops', as:'gro', cond:{$eq:['$$gro.id','a1']}}}})
/*
{ "_id" : ObjectId("600d357fb9f5ffd060ed064e"), "addOp" : [ { "id" : "a1" } ] }
note: we have "removed" the intermediary need to traverse "prices"
*/
Finally if we assume only one addOperation can match (which would be natural since we target an id)
$first can get the first elem of the array
filter = {$filter: {input:'$prices.ops', as:'addOp', cond:{$eq:['$$addOp.id','a1']}}}
db.dummy.find(query,{'addOp': {$first: filter}})
{ "_id" : ObjectId("600d357fb9f5ffd060ed064e"), "addOp" : { "id" : "a1" } }
some playground
edit: mongoose wise, probably stop yourself at the array.$ to respect the mongoose schema
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost:27017/dummy')
const Stock = mongoose.model('Stock', {
prices:{
id: String,
ops:[{id:String}]
}
}, 'dummy');
;(async()=>{
mongoose.set('debug', true)
const query = {'prices.ops.id':'a1', 'prices.id': 'a'}
const v = await Stock.find(query).select('prices.ops.$')
console.log('s : ', JSON.stringify(v.map(s => s.toJSON()), null, 2))
mongoose.disconnect()
})()
/*
Mongoose: dummy.find({ 'prices.ops.id': 'a1', 'prices.id': 'a' }, { projection: { 'prices.ops.$': 1 } })
s : [
{
"prices": {
"ops": [
{
"id": "a1"
}
]
},
"_id": "600d357fb9f5ffd060ed064e"
}
]
*/