Why $ne: null returning the empty arrays? - javascript

I`m trying to return the arrays are that have contents but $ne: null or $exsists: true still returning the empty arrays..
const userSchema = new mongoose.Schema({
email: String,
password: String,
googleId: String,
facebookId: String,
secret: Array
});
app.get("/secrets", function(req, res) {
User.find({secret: {$ne: null} }, function(err, secrets) {
if (err) {
console.log(err);
} else {
if (secrets) {
console.log(secrets);
res.render("secrets", {
secrets: secrets
});
};
};
});
});
I googled quite a bit about it and I do understand that $ne: null would return every document where the secret array doesn't exists, but if its an empty array then why? Any suggestion how to overcome this rookie problem? Im new here be kind! :)

This is because null != [].
You will have to explicitly write your condition to handle both.
$nin is for not in. So find users where secret value is not in the given array. The given array can hold your multiple values.
User.find({secret: {$nin: [null, [] ] } },...
Also, with $exists you will even get docs where the field is null. The only docs you will not get are the ones where the secret field does not exist at all.

If the documents contain values for the secret field that include missing/undefined, null, empty array, and populated array, you have a few options to only match populated arrays:
{$eval:{$gt:[0,{$size:"$secret"}]}}- get the size for thesecrets` array, and only match arrays that are not empty.
{"secret.0":{$exists:true}} - only match the document if there is a first element in the secret array (implicitly doesn't match non-array fields)
If the elements in the secret array are all the same type, a type-based query can be used. For example, if the elements in the secret array are strings, {"secret.0":{$gte:""}} will match any array whose first element is a string. This could also be optimized by creating an index on {"secret.0":1}

Related

Mongoose - Deleting documents is unresponsive

I'm trying to use Mongoose (MongoDB JS library) to create a basic database, but I can't figure out how to delete the documents / items, I'm not sure what the technical term for them is.
Everything seems to work fine, when I use Item.findById(result[i].id), it returns a valid id of the item, but when I use Item.findByIdAndDelete(result[i].id), the function doesn't seem to start at all.
This is a snippet the code that I have: (Sorry in advance for bad indentation)
const testSchema = new schema({
item: {
type: String,
required: true
},
detail: {
type: String,
required: true
},
quantity: {
type: String,
required: true
}
})
const Item = mongoose.model("testitems", testSchema)
Item.find()
.then((result) => {
for (i in result) {
Item.findByIdAndDelete(result[i].id), function(err, result) {
if (err) {
console.log(err)
}
else {
console.log("Deleted " + result)
}
}
}
mongoose.connection.close()
})
.catch((err) => {
console.log(err)
})
I'm not sure what I'm doing wrong, and I haven't been able to find anything on the internet.
Any help is appreciated, thanks.
_id is a special field on MongoDB documents that by default is the type ObjectId. Mongoose creates this field for you automatically. So a sample document in your testitems collection might look like:
{
_id: ObjectId("..."),
item: "xxx",
detail: "yyy",
quantity: "zzz"
}
However, you retrieve this value with id. The reason you get a value back even though the field is called _id is because Mongoose creates a virtual getter for id:
Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it by passing this option at schema construction time.
The key takeaway is that when you get this value with id it is a string, not an ObjectId. Because the types don't match, MongoDB will not delete anything.
To make sure the values and types match, you should use result[i]._id.

Mongoose array in document does not exist when queried

I need to query for all documents with an array but the returned documents dont have the array.
query
(async () => {
const data = await Lesson.find({signed: {$exists: true}});
console.log(data[0].signed); # undefined
})();
model
const lessonSchema = new mon.Schema(
{
day: Number,
startTime: Number,
endTime: Number,
description: {type: String, trim: true},
signed: [mon.Schema.Types.ObjectId]
},
{
collection: 'lessons'
}
);
module.exports = mon.model("Lesson", lessonSchema);
I checked the database and the documents do have the array.
The query retrieve everything except for the array (all of the documents and their values except for the array).
NOTE: in the database I have only two test documents. both have an array and both don't have the array in the query.
Thanks
EDIT: I found out that if I remove the signed property from the schema it works. Why?
I had this problem because the type of signed was objectId and the ids I used were strings. I cleared the array and added real ObjectId and it worked.

How do I find documents by name only with NeDB?

I'm trying to find documents by only the document name in NeDB. I have read through the documentation, but all examples also search on a value. I am only inserting one document, and need to query by its name only.
const Datastore = require('nedb')
, db = new Datastore({ filename: './data/database.json', autoload: true })
db.find("myDocName", (err, docs)=>{ // this returns no results even though the document exists
if(docs[0]){
console.log(docs[0])
} else {
database.db.insert({myDocName: {some: "data"})
}
})
I have also tried matching any value with regular expressions, to no avail:
let regEx = /.*/
database.db.find({"myDocName":regEx}, (err, docs)=>{
....
it seems that the $exists operator might be exactly that what you are looking for:
db.find({myDocName: {$exists: true}}, (err, docs)=>{
...
});

Exclude a field in Mongoose wile using assignment operator for Query

I am aware that this question has been asked before. Sites often give the solution using .select('-queryData')however I do not know how to use it for my scenario.
I have a DB with the following schema
let TestSchema = new Schema ({
..
test: {type: String, required: true},
arrayField: {type: Array, required: true},
..
});
I have to query the arrayField where it should not include 'data1'. If it includes this value then that object should not be shown.
However I am using assignment operator for query object, instead of calling the function '.select()'. Hence I tried adding it in the query JSON itself, but it did not work.
index.js
let query = {};
query.test = "Hello";
query.arrayField = '-data1'; //Change needed here
TestSchema.find(query, function(err, result){
if(err){
console.log(err);
}else{
console.log(result);
}
});
I tried checking various sites for a specific solution to such a scenario, however I could not get any conclusive solution.
You can use $exists mongodb operator for your query.
TestModel.find({ test: "Hello", "arrayField.data1": { $exists: false } })
Select method has a different use case which is to select or limit the fields returned as a result of a query. And you need to execute find method on TestModel not TestSchema.
const TestModel = mongoose.model("TestModel", TestSchema);
You should use the $exists operator, here's an example:
TestModel.find({
test: "Hello",
"arrayField.$.data1": {
$exists: false
}
}, function(err, result){
if(err){
console.log(err);
}else{
console.log(result);
}
});

Remove key with empty array value in mongodb

When I have one item left in an array and I remove it, the field becomes empty. Is there any option to check if there is one element left and then update the key with undefined instead of removing?
Here is what I have:
User.aggregate([
{$match: {email: {$in: [email, friendEmail]}}},
{
$project: {
friendSentRequests: {$size: {"$ifNull": ["$friendSentRequests", []]}},
friendReceivedRequests: {$size: {"$ifNull": ["$friendReceivedRequests", []]}},
}
}],
(err, result) => { ... }
);
With method written above I indeed get the array size, but batch throws errors that array is type missing if one doc doesn't have the key that second doc has. Unless I'm not supposed to make any updates in (err, result) => {..} function and there is another recommended way to update the object.
I don't want to set multi because I want to update via batch two different keys from different docs and I can't get the array length of each of these fields. Unless I'm misunderstanding how multi works.
if you want to confirm the number of elements in an array , e.g here is you want to check that the array has one element then:
{
$match:{
"myArray" :{ $size : 1 }
}
}
And to check if array does not exist:
{
$match:{
"myArray" :{ $exists: false}
}
}

Categories