I have documents like this:
db.planet.insert({
name: 'Earth',
stuff: {
'grass': 'green',
'sky': 'blue',
'sea': 'blue'
}
})
db.planet.insert({
name: 'Mars',
stuff: {
'dust': 'red',
'sky': 'yellow'
}
})
I want to find all planets that have at least some blue stuff (only earth in this case). How can I do that?
Catch: I tried solving this by using an array (instead of object) for stuff (stuff: [ { k: 'grass', v: 'green'},... ]) but I also need to be able to update (upsert to be exact) value of some stuff. For instance I must be able to do this:
db.planet.update({ name: 'Mars' }, {
'$set': {
'stuff.canals': 'brown',
'stuff.dust': 'reddish'
}
})
So, how can I find the planets with something blue on them? :)
Use the $or operator. The $or operator value should be an array, with the array containing conditions of which at least one must be true.
In your case, given the field names you have mentioned:
db.planet.find($or:[
{"stuff.sky":"blue"},
{"stuff.grass":"blue"},
{"stuff.sea":"blue"},
{"stuff.dust":"blue"},
{"stuff.canals":"blue")
])
See http://docs.mongodb.org/manual/reference/operator/or/
As there are a quite a number of different fields you want to query, you may want to keep an array of all these field names somewhere so you can generate the $or array programmatically.
I don't think there's a way to make the query without knowing the field names in advance. See mongodb query without field name .
Related
I want to find entries in my MongoDB collection that match some filters.
Each entry in my mongo collection looks like this data:
{
type: "admin"
senderId: "6131e7c597f50700160703fe"
read_by: [
{
Object_id: 614dbbf83ad51412f16c0757
readerId: "60b968dc5150a20015d6fcae"
}
]
},
{
type: "admin"
senderId: "6131e7c597f50700160703fe"
read_by: [
{}
]
}
What I want to achieve properly, is to filter on the collection and get only the entries that match 'admin' as type and that don't have the current user's ID in the read_by array (that is an array of objects)
I wrote this (and tried some other combinations with errors :) )
but it is not working, I get 0 entries on the end, but I expect to get one of the two as the second have it's read_by array empty.
Thank you very much!
I validated my solution using cloud.mongodb.com interface and the simplest following filter seems to do the job:
{ "read_by.readerId": {$ne:"60b968dc5150a20015d6fcae"}}
Only the record with empty array is being returned.
$nin operator works fine as well but if there is only single value for comparision then $ne should be enough.
{ "read_by.readerId": {$nin: ["60b968dc5150a20015d6fcae"]}}
I'm trying to update an array that sits inside another array in a document. The schema is like this:
const projectSchema = new mongoose.Schema({
stakeholders: [{
stakeholderTitle: {
type: String,
},
...
subgroup: [{
subgroupTitle: {
type: String
},
subgroupPercent: {
type: Number,
}
}]
}],
and I'm trying to update the 'subgroup' array. I have got the query to work on its parent (the stakeholder array) with the positional $ operator, using the answer to this question I asked previously. So my query looks like this.....
await db.findOneAndUpdate({ find by the id }, { "stakeholders.$.stakeholderTitle": req.body.stakeholderTitle, ... "stakeholders.$.subgroup": req.body.subgroup })
However, this query doesn't work for the 'stakeholders subgroup' array, and makes it null. Looking through the mongo docs for the positional operator it states that 'The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value', which I guess might be my problem.
So how can I do this with a findOneAndUpdate query?
From what I see is you have to specify the object you want to update inside the subgroup array. Try this - (i.e I'm updating the subgroupTitle of the subgroup array);
await db.findOneAndUpdate(
{
_id: userId,
"stakeholders.stakeholderTitle": req.body.stakeholderTitle,
"stakeholders.stakeholderTitle.subgroup.subgroupTitle": req.body.subgroupTitle
},
{$set: {
"stakeholders.stakeholderTitle.subgroup.$.subgroupPercent": somePercentValue,
}
},
);
Also note, it's only the array that you find that you can update. It might not be exactly what you want, but its a step closer
In the algolia documentation, they specify that you can manipulate arrays like this:
// adding
index.partialUpdateObject({
myfield: {
value: 'myvalue',
_operation: 'Add'
},
objectID: 'myID'
})
/removing
index.partialUpdateObject({
myfield: {
value: 'myvalue',
_operation: 'Remove'
}
})
This works well when the array is a string or number. However imagine that I have this document structure, where arrays are actually nested objects:
{
first_name: String,
last_name: String,
subjects: [
{
itemId: String,
title: String,
randomField: String,
dateAdded: Date
}
]
}
In this case the algolia documentation is very unclear. For example, imagine the following scenarios:
I want to update the randomField field of a particular array item. I want to be able to update a nested array item by itemId.
I want to be able to add or remove nested array items. In this case, what do I pass into the "value" field when doing a partialUpdateObject.
Is this kind of thing possible in Algolia? What would be your recommendations?
It's not possible to add/update/remove a specific attribute of a nested array using the partilUpdateObject function.
You get it right by fetching the object, modifying and updating it after. :)
It’s still true that you can’t update individual key value with in a nested object
All!
My document has such structure:
{
fname: value,
lname: value,
city: value
}
When I use find() method, I get result in default order fname, lname, city.
But I want to get result in other order of field, such as: city, fname, lname.
Does mongodb allow fields ordering in result?
Yes and no. To really do this sort of manipulation you need the aggregation framework. Even then it's a bit tricky since you must "rename" the fields in order to change their order. This is because there are general optimizations in place that "copy" content from one "pipeline" stage to another. This is considered optimal.
But you can always do this:
db.collection.aggregate([
{ "$project": {
"tcity": "$city",
"tfname": "$fname",
"tlname": "$lanme"
}},
{ "$project": {
"city": "$tcity",
"fname": "$tfname",
"lname": "$tlname"
}}
])
Very contrived, but that is the way you have to do it. Or otherwise just live with a single projection for the "renamed" fields in the order you want and then just "rename" again in code.
Or of course, your code can simply "re-map" the field names from the result of a query.
But the basic point is that MongoDB itself "preserves" the original order of fields as an "optimization" to how they are stored and does not mess with the output otherwise. If you want to you can, but you need to take the steps as shown in order to do so.
You can use .sort(). eg:
db.stocks.find().sort( { ticker: 1, date: -1 } )
For more info see http://docs.mongodb.org/manual/reference/method/cursor.sort/
I assume you are referring to the output as it shows up in the Mongo shell? If so, you can assign the returned output to a variable (cursor, I believe) and step through your cursor afterwards while outputting the individual field variables in any order you like.
Is there a way of sorting in MongoDB based on an $elemMatch? For example, I have documents which look like this:
{
'user': ObjectId('fsdfsdf'),
...
'array_of_things': [
{
'attribute_1': ObjectId('sdfsdfsd'),
'attribute_2': ObjectId('sdfsfsdf'),
'value': 30000
},
{
'attribute_1': ObjectId('dfdfgfdg'),
'attribute_2': ObjectId('gdfgdfgd'),
'value': 100
},
{
'attribute_1': ObjectId('mbnmbbmb'),
'attribute_2': ObjectId('mbnmbnmb'),
'value': 2000
},
...
]
}
I need to be able to query this data based on a matching element inside the array_of_things field (which is simple enough with an $elemMatch). The problem arises because I also need to be able to sort by value (ascending or descending) that match a certain attribute. For example, a query might be:
{
'user': ObjectId('fsdfsdf'),
'array_of_things': {
$elemMatch: {
'attribute_1': ObjectId('dfdfgfdg'),
'value': {
$gt: 1
}
}
}
}
Sorting solely on value (e.g. sort({ 'array_of_things.value': -1 }) predictably only sorts on all values in any array element, not matching attribute_1 first.
Is there a way to do this?
Apologies if this is an already-asked question, but I can't seem to find any solution to it after looking.
This is currently not possible with the standard query language. You can achieve it with the aggregation framework at (potentially) some performance penalty.