I inputed a parameter, and using mongodb.
My query is
db.collections.find({"tags":parameter});
I want to run query, when parameter is "" (null or "").
It will be
db.collections.find({"tags":""});
It is returned empty value.
How can I use input parameter null or "" in mongoDB?
EDIT
I'm sorry. I'm beginner in here, so sorry.
I want to get all the values returned when I type null
For example, it looks like this my collections,
collections
{
"_id": 0,
"tags": ["happy", "sad", "nice", "bad"]
},
{
"_id": 1,
"tags": ["bad", "gloomy"]
}
I want the same result as below.
> Db.collections.find ({"tags": ""})
{
"_id": 0,
"tags": ["happy", "sad", "nice", "bad"]
},
{
"_id": 1,
"tags": ["bad", "gloomy"]
}
// Return all collections.
> Db.collections.find ({"tags": "happy"})
{
"_id": 0,
"tags": ["happy", "sad", "nice", "bad"]
}
// Return matching collections.
but, db.collections.find ({"tags": ""}) brings out the results of that result is empty.
How can I print out all the results when I enter a null value?
Since a null value can be represented in several ways, depending on the language that wrote to the database in the first place, you need to use a combinations of things. Your query will need to look something like
db.collection.find({$or:[{"tags":{"$type":"null"}}, {"tags": {"$exists":false}}, {"tags":""}]})
Since BSON has a concept of Null, we have type check to see if the field exists but simply has no value. In addition to this, the field could not exist at all, so this must be explicitly checked for. Finally, depending on the language and the way the field was serialized, an empty string is a possibility.
Note that
{"tags":null}
and
{"tags":{"$type":"null"}}
are essentially the same thing.
Here is a quick example
> db.test.insert({"abc":null})
WriteResult({ "nInserted" : 1 })
> db.test.find()
{ "_id" : ObjectId("56670b3072f096ee05a72063"), "abc" : null }
> db.test.find({"abc":{$type:10}})
{ "_id" : ObjectId("56670b3072f096ee05a72063"), "abc" : null }
> db.test.find({"abc":{$type:"null"}})
{ "_id" : ObjectId("56670b3072f096ee05a72063"), "abc" : null }
> db.test.find({"abc":null})
{ "_id" : ObjectId("56670b3072f096ee05a72063"), "abc" : null }
db.test.find({$or:[{"tags":{"$type":"null"}}, {"tags": {"$exists":false}}, {"tags":""}]})
{ "_id" : ObjectId("56670b3072f096ee05a72063"), "abc" : null }
As you can see they all work, although the last query is the most thorough way of testing.
EDIT OP CHANGED QUESTION
You cannot find all values when you type null. That is a value and potential state for a field. You need to do an implicit $and here to get what you want.
db.collection.find({tags:{$exists:true}, tags:{$in:["happy","sad"]}})
How do you actually assemble this in code? Well, that depends on your language, but here is some pseudo code.
def getTags(myTags):
if (tags is None):
db.collection.find({ tags: { "$exists": true } })
else:
db.collection.find({ tags: { "$exists": true }, tags: {"$in": myTags } })
You can also get crafty by using an explicit $and
def getTags(myTags):
query = [{ tags: { "$exists": true } }]
if (tags is Not None):
query.add({tags: {"$in": myTags } })
db.collection.find({ "$and": query })
I hope this answers your question more thoroughly.
The accepted answer isn't suitable for the question(at least nowadays).
In MongoDB >= 3.6.
you can use the $expr operator as follow :
assuming that your parameter name is tagsParam and its value may be an Array or null
db.collections.find({
$or: [
{ $expr: !tagsParam || !tagsParam.length },
{ tags: { $in: paramter } }
]
});
In this case you will get the desired result if the parameter value was ["happy"], null or even an empty array [].
Related
I have a JSON in MongoDB and I am trying to check if at least one of the items in the JSON doesn't contain a specific field.
{
"_id" : 12345,
"orderItems" : [
{
"itemId" : 45678,
"isAvailable" : true,
"isEligible" " false
},
{
"itemId" : 87653,
"isAvailable" : true
}
]
}
So in the above JSON, since the 2nd one under order items doesn't contain iseligible field, I need to get this _id.
I tried the below query so far, which didnt work:
db.getCollection('orders').find({"orderItems.iseligible":{$exists:false})
You can use $elemMatch to evaluate the presence of the nested key. Once that's accomplished, project out the _id value.
db.orders.find({
orderItems: {
$elemMatch: {
"isEligible": {
$exists: false
}
}
}
},
{
_id: 1
})
Here is a Mongo playground with the finished code, and a similar SO answer.
I don't understand the behaviour of the command $exists.
I have two simple documents in the collection 'user':
/* 1 */
{
"_id" : ObjectId("59788c2f6be212c210c73233"),
"user" : "google"
}
/* 2 */
{
"_id" : ObjectId("597899a80915995e50528a99"),
"user" : "werty",
"extra" : "very important"
}
I want to retrieve documents which contain the field "extra" and the value is not equal to 'unimportant':
The query:
db.getCollection('users').find(
{"extra":{$exists:true},"extra": {$ne:"unimportant"}}
)
returns both two documents.
Also the query
db.getCollection('users').find(
{"extra":{$exists:false},"extra": {$ne:"unimportant"}}
)
returns both two documents.
It seems that $exists (when used with another condition on the same field) works like an 'OR'.
What I'm doing wrong? Any help appreciated.
I used mongodb 3.2.6 and 3.4.9
I have seen Mongo $exists query does not return correct documents
but i haven't sparse indexes.
Per MongoDB documentation (https://docs.mongodb.com/manual/reference/operator/query/and/):
Using an explicit AND with the $and operator is necessary when the same field or operator has to be specified in multiple expressions.
Therefore, and in order to enforce the cumpliment of both clauses, you should use the $and operator like follows:
db.getCollection('users').find({ $and : [ { "extra": { $exists : true } }, { "extra" : { $ne : "unimportant" } } ] });
The way you constructed your query is wrong, nothing to do with how $exists works. Because you are checking two conditions, you would need a query that does a logical AND operation to satisfy the two conditions.
The correct syntax for the query
I want to retrieve documents which contain the field "extra" and the
value is not equal to 'unimportant'
should follow:
db.getCollection('users').find(
{
"extra": {
"$exists": true,
"$ne": "unimportant"
}
}
)
or using the $and operator as:
db.getCollection('users').find(
{
"$and": [
{ "extra": { "$exists": true } },
{ "extra": { "$ne": "unimportant" } }
]
}
)
I have a data
[{ "name":"BS",
"keyword":"key1",
"city":"xyz"
},
{ "name":"AGS",
"keyword":"Key2",
"city":"xyz1"
},
{ "name":"QQQ",
"keyword":"key3",
"city":"xyz"
},
{ "name":"BS",
"keyword":"Keyword",
"city":"city"
}]
and i need to search records which have name= "BS" OR keyword="key2" with the help of query
db.collection.find({"$OR" : [{"name":"BS"}, {"keyword":"Key2"}]});
These records i need in the sequence
[{ "name":"BS",
"keyword":"key1",
"city":"xyz"
},
{ "name":"BS",
"keyword":"Keyword",
"city":"city"
},
{ "name":"AGS",
"keyword":"Key2",
"city":"xyz1"
}]
but i am getting in following sequences:
[{ "name":"BS",
"keyword":"key1",
"city":"xyz"
},
{ "name":"AGS",
"keyword":"Key2",
"city":"xyz1"
},
{ "name":"BS",
"keyword":"Keyword",
"city":"city"
}]
Please provide some suggestion i am stuck with this problem since 2 days.
Thanks
The order of results returned by MongoDB is not guaranteed unless you explicitly sort your data using the sort function. For smaller datasets you maybe "lucky" in the sense that the results are always returned in the same order, however, for bigger datasets and in particular when you have sharded Mongo clusters this is very unlikely. As proposed by Yathish you need to explicitly order your results using the sort function. Based on the suggested output, it seems you want to sort by name in descending order so I have set the sorting flag to -1 for the field name.
db.collection.find({"$or" : [{"name":"BS"}, {"keyword":"Key2"}]}).sort({"name" : -1});
If you need a more complex sorting algorithm as specified in your comment, you can convert your results to a Javascript array and create a custom sort function. This sort function will first list documents with a name equal to "BS" and then documents containing the keyword "Key2"
db.data.find({
"$or": [{
"name": "BS"
}, {
"keyword": "Key2"
}]
}).toArray().sort(function(doc1, doc2) {
if (doc1.name == "BS" && doc2.keyword == "Key2") {
return -1
} else if (doc2.name == "BS" && doc1.keyword == "Key2") {
return 1
} else {
return doc1.name < doc2.name
}
});
In my database I have a field of name. In some records it is an empty string, in others it has a name in it.
In my query, I'm currently doing:
db.users.find({}).sort({'name': 1})
However, this returns results with an empty name field first, then alphabetically returns results. As expected, doing .sort({'name': -1}) returns results with a name and then results with an empty string, but it's in reverse-alphabetical order.
Is there an elegant way to achieve this type of sorting?
How about:
db.users.find({ "name": { "$exists": true } }).sort({'name': 1})
Because after all when a field you want to sort on is not actually present then the returned value is null and therefor "lower" in the order than any positive result. So it makes sense to exclude those results if you really are only looking for something with a matching value.
If you really want all the results in there and regarless of a null content, then I suggest you "weight" them via .aggregate():
db.users.aggregate([
{ "$project": {
"name": 1,
"score": {
"$cond": [
{ "$ifNull": [ "$name", false ] },
1,
10
]
}
}},
{ "$sort": { "score": 1, "name": 1 } }
])
And that moves all null results to the "end of the chain" by assigning a value as such.
If you want to filter out documents with an empty "name" field, change your query: db.users.find({"name": {"$ne": ""}}).sort({"name": 1})
In MongoDB, using $type, it is possible to filter a search based on if the field matches a BSON data type (see DOCS).
For eg.
db.posts.find({date2: {$type: 9}}, {date2: 1})
which returns:
{
"_id" : ObjectId("4c0ec11e8fd2e65c0b010000"),
"date2" : "Fri Jul 09 2010 08:25:26 GMT"
}
I need a query that will tell me what the actual type of the field is, for every field in a collection. Is this possible with MongoDB?
Starting from MongoDB 3.4, you can use the $type aggregation operator to return a field's type.
db.posts.aggregate(
[
{ "$project": { "fieldType": { "$type": "$date2" } } }
]
)
which yields:
{
"_id" : ObjectId("4c0ec11e8fd2e65c0b010000"),
"fieldType" : "string"
}
type the below query in mongo shell
typeof db.employee.findOne().first_name
Syntax
typeof db.collection_name.findOne().field_name
OK, here are some related questions that may help:
Get all field names in a collection using map-reduce.
Here's a recursive version that lists all possible fields.
Hopefully that can get you started. However, I suspect that you're going to run into some issues with this request. There are two problems here:
I can't find a "gettype" function for JSON. You can query by $type, but it doesn't look like you can actually run a gettype function on a field and have that maps back to the BSON type.
A field can contain data of multiple types, so you'll need a plan to handle this. Even if it's not apparent Mongo could store some numbers as ints and others floats without you really knowing. In fact, with the PHP driver, this is quite possible.
So if you assume that you can solve problem #1, then you should be able to solve problem #2 using a slight variation on "Get all field Names".
It would probably look something like this:
"map" : function() { for (var key in this) { emit(key, [ typeof value[key] ]); } }
"reduce" : function(key, stuff) { return (key, add_to_set(stuff) ); }
So basically you would emit the key and the type of key value (as an array) in the map function. Then from the reduce function you would add unique entries for each type.
At the end of the run you would have data like this
{"_id":[255], "name" : [1,5,8], ... }
Of course, this is all a lot of work, depending on your actual problem, you may just want to ensure (from your code) that you're always putting in the right type of data. Finding the type of data after the data is in the DB is definitely a pain.
Taking advantage of the styvane query, I added a $group listing to make it easier to read when we have different data types.
db.posts.aggregate(
[
{ "$project": { _id:0, "fieldType": { "$type": "$date2" } } },
{"$group": { _id: {"fieldType": "$fieldType"},count: {$sum: 1}}}
])
And have this result:
{ "_id" : { "fieldType" : "missing" }, "count" : 50 }
{ "_id" : { "fieldType" : "date" }, "count" : 70 }
{ "_id" : { "fieldType" : "string" }, "count" : 10 }
Noting that a=5;a.constructor.toString() prints function Number() { [native code] }, one can do something similar to:
db.collection.mapReduce(
function() {
emit(this._id.constructor.toString()
.replace(/^function (\S+).+$/, "$1"), 1);
},
function(k, v) {
return Array.sum(v);
},
{
out: { inline: 1 }
});