Query model against value within a list - node.js

When I query a user from its email:
User.findOne({email: 'a#a.com'}).done(function(err, u){console.log(u.sessionTokens);})
I got its tokens list:
[ { token: '8dfe6aa0-2637-4b3f-9a3c-3ae8dc225b77',
issuedAt: Tue Jan 14 2014 14:40:22 GMT+0100 (CET) } ]
But when I query a token within this list it does not retrieve the user:
User.findOne({'sessionTokens.token':'8dfe6aa0-2637-4b3f-9a3c3ae8dc225b77'}).done(function(err, u){console.log(u);})
=> undefined
Any ideas ?
Does the User.findOne({'sessionTokens.token':'8d...77'}) is a correct query ?
EDIT
My User model is something like:
module.exports = {
schema: true,
attributes: {
email: {
type: 'email',
required: true
},
encryptedPassword: {
type: 'string'
},
sessionTokens: {
type: 'array'
},
...
}
}
sessionToken is an attribute of type Array. This array contains several object like:
{ token: '8dfe6aa0-2637-4b3f-9a3c-3ae8dc225b77',
issuedAt: Tue Jan 14 2014 14:40:22 GMT+0100 (CET) }
EDIT
I've tested with mongo-sails instead of mongo-disk, this is working fine but as Chad pointed this out, it depends of the adapter used.

With the help of robdubya & sfb_ in #sailsjs#freenode, we discussed a solution for this a bit. The answer depends on the adapter you are using. The adapter that I am most familiar with is the mysql adapter, and in that adapter, the 'array' attribute type gets serialized to the database as a JSON string. So in that case, using the 'contains' modifier on the query of the model would allow you to find the record you are looking for:
var criteria = {
sessionToken: {
contains: '8dfe6aa0-2637-4b3f-9a3c-3ae8dc225b77'
}
};
User.findOne(criteria).done(function (err, user) {
...
});

Related

Speed up Slow Mongo / Mongoose Query

I have a the following model and indexes:
var mySchema = new Schema({
page: String,
date: Date,
data: Object,
_page: {
type: Schema.Types.ObjectId,
ref: 'Page'
},
});
mySchema.index({_page: 1, date: 1 }, {unique: true});
And this query:
mySchema.find({
_page: page._id,
date: {
$gte: date1,
$lt: date2
}
})
.sort({
date: 1
})
.exec((err, result) => {
console.log(result);
})
And it logs out like this:
myschema.find({ date: { '$gte': new Date("Thu, 16 Nov 2017 23:00:00 GMT"), '$lt': new Date("Thu, 14 Dec 2017 23:00:00 GMT") }, _page: ObjectId("5a57b30bf54be100c315f2f5") }, { sort: { date: 1 }, fields: {} })
And it takes about 1 second to return ~30 results from a table with about 4000 documents and ~60mb.
DB is a replica cluster on mlab, query speed is pretty similar weather I connect from localhost or my server (db and server in w-europe)
Is there any way to speed this up? Am I indexing or querying wrong?
Using lean() method can improve the performance of find query in mongoose. The reason for it is that using this function returns plain Javascript objects instead of extra Mongoose methods like save function, getters and setters. If you want to check the performance difference of a plain Javascript object and Mongoose Object, you can visit this link
However, you can take advantage of it for only read operations. So, if its just find operation, you can use lean().
mySchema.find(...).lean().exec(function(err, docs) {
...
});

Why mongoose populate return me an illegal array and how to do with it?

I use mongoose populate a list of data like:
Account.findOne({_id:accountId}).populate({
path:"orders.order",
match:{_id:orderId},
selecte:'',
options:{
limit:1
}
}).exec(function (err, doc) {
if (err) {
callback(err);
}
callback(doc);
})
}
and what I get:
[ { order: null },
{ order: null },
{ order: null },
{ order: null },
{ order: null },
{ order: null },
{ order:
{ date: Tue May 31 2016 12:56:36 GMT+0800 (HKT),
dishs: [Object],
__v: 0,
message: 'plz deliver after 5 p.m',
price: 5,
address: [Object],
shop: null,
user: 574bfebc29cf722c17f8eafe,
_id: 574d198451615ce01a5e1a81 } } ]
I think this data is an array, but
console.log(typeof doc.orders);//object
console.log(doc.orders.length);//undefined
console.log(doc.orders[0].order);//error
console.log(Array.isArray(doc.orders));//false
I do not know how to delete null value of this data and how to change this data into an array?
By the way, I find a post in gist said that mongoose populate.match will return null value if it did not match the condition, is that true?
I make mistake that I define the schema the wrong way.
The wrong schema:
orders:{order: [{type: mongoose.Schema.Types.ObjectId, ref:'Order'}] }
The right way the define schema in array which you what to populate:
orders:{type:[{
order:{type: mongoose.Schema.Types.ObjectId, ref:'Order'}
}]}
After this, use populate.match will give you an legal array and your could do with it like normal array.

Retrieving model using mongoose

I want to retrieve the whole model from my database searching by an "id".
Which query is best to use in this case?
This is how my schema looks:
{ _id: 54b5ed4b967a4e3b96fe8a39,
email: 'blabla#yahoo.com',
__v: 0,
deleted: false,
createdAt: Tue Jan 13 2015 23:15:07 GMT-0500 (EST),
shipping: {},
profile: { picture: '', location: 'Romania', name: 'bla' },
tokens: [],
role: 'shopper'}
and what I have is: 54b5ed4b967a4e3b96fe8a39
If you know the type of Model that you are looking for, i.e. Person. Just do:
var id = "54b5ed4b967a4e3b96fe8a39";
Person.findById(id, function(err, person) {
if (err) {
return console.log('oh no! error', err);
}
console.log('found person', person);
});
Documentation here

mongoose returning duplicate results

Pretty new to mongo and mongoose.
I have
var mongoose = require('mongoose'),
errorHandler = require('./errors'),
ClientSummary = mongoose.model('ClientSummary');
exports.list = function(req, res) { ClientSummary.find().sort('-LastName').exec(function(err, clients) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
console.log(clients);
res.jsonp(clients);
}
});
};
this returns double results for each client
I copied this from the console
[ { _id: '_?\u0007Z?WM???3\u0016?\u0017',
ArchivedDate: Sun Dec 31 0 18:00:00 GMT-0600 (Central Standard Time),
ArchiveDate: Sat Nov 08 2014 17:18:55 GMT-0600 (Central Standard Time),
Archived: false,
Phone: null,
EmailAddress: 'test#test.com',
LastName: 'test',
FirstName: 'test' },
{ _id: '??\u0002otsF???\u000fF\u0010\u0019\n',
ArchivedDate: Sun Dec 31 0 18:00:00 GMT-0600 (Central Standard Time),
ArchiveDate: Sat Nov 08 2014 17:18:55 GMT-0600 (Central Standard Time),
Archived: false,
Phone: null,
EmailAddress: 'test#test.com',
LastName: 'test',
FirstName: 'test' } ]
I get this from a query
db.clients.find()
{ "_id" : BinData(4,"U/UnaPQyRxqtc1iPJP7Lyw=="), "Contact" : { "FirstName" : "test", "LastName" : "test", "EmailAddress" : "test#test.com", "Phone" : null, "PhoneSecondary" : null }, "Address" : null, "Source" : null, "SourceNotes" : "asdf", "Archived" : false, "ArchivedDate" : ISODate("0001-01-01T00:00:00Z"), "StartDate" : ISODate("0001-01-01T00:00:00Z") }
any thoughts would be greatly appreciated
Thanks,
Raif
I do not see why you are saying that you have duplicate results in the first query. The _ids are different, so, it looks like there are two different objects.
Further, I also think that the second query that you have refers to a different collection; i.e. clients, while the first query refers to the collection clientsummary.
For example, use the mongo shell, connect to the db *, and try the following two:
> show collections
If I am right, you have both clients and clientsummary as collections in your db. Then, also try
> db.clientsummary.count()
This should return 2.
Note, that it might be the case that you have clientSummary instead of clientsummary as collection in your db, or even clientsummarys/clientSummarys or clientsummaries/clientSummaries as mongo/mongoose will use the plural for the collection and an s is usually attached in the end of the word referring to the collection. Just use the right name.
(*) You can connect to the db mydb (where the collections you are referring to can be found) using the command:
$ mongo --shell localhost/mydb
(Assuming you have mydb on localhost.)

Mongoose schema validate without creating a document

Say I have a javascript object (the data) and I want to check to see if it conforms to a given Schema that I've defined.
Is there a way to do this without turning the schema into a model, creating an instance of that model populated with the data, and running mymodel.validate()?
I'd love to have a Schema(definition).validate(data, callback), but the validate function is defined on the Document class, from what I could tell.
2021 update
Mongoose added that functionality as Model.validate(...) back in 2019 (v5.8.0):
You can:
try {
await Model.validate({ name: 'Hafez', age: 26 });
} catch (err) {
err instanceof mongoose.Error.ValidationError; // true
}
One way is to perform that with the help of custom validators. When the validation declined, it failed to save the document into the database.
Or another way to do that through validate() function provided by MongoDB with the same schema as you defined.
You can validate your schema on the Mongo side link
For example:
db.createCollection("students", {
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "name" ],
properties: {
name: {
bsonType: "string",
description: "must be a string and is required"
},
year: {
bsonType: "int",
minimum: 2017,
maximum: 3017,
description: "must be an integer in [ 2017, 3017 ] and is required"
}
}
}
}
})

Resources