Trying to find record using $in in mongoose - node.js

I'm trying to find record using $in in mongoose. But it's not working for me. I have same query in mongo shell its working but in mongoose it is not workinh
my schema
{
"_id": "574f1f979f44e7531786c80f",
"name": "mySchool2",
"branch": "karachi",
"location": "Clifton ",
"block": false,
"created_at": 1464803223441,
"updated_at": 1464803223441,
"__v": 0,
"classes": [
"574f216afd487958cd69772a"
],
"admin": [
"574f20509f44e7531786c811",
"57508a2a3a0a919c16ace3c0"
],
"teacher": [
"574f20f39f44e7531786c812",
"575002b48188a3f821c2a66e",
"57500bbaea09bc400d047bf6"
],
"student": [
"574f2d56590529c01a2a473b",
"574f2e5842c5885b1b1729ab",
"574f2ed542c5885b1b1729ae",
"574f2f57555210991bf66e07",
"574f2fcd087809b11bd8d5e4",
"574f301d1f5025d61b7392b6",
"574f30481d02afff1bb00c71",
"574f30b01d02afff1bb00c74",
"574f310038136b3d1cf31b96"
]
}
My mongose query
app.services._chkAdminSchool = function(payload){
var deferred = q.defer();
School
//.find({ teacher:{$in:['574f20f39f44e7531786c812']}})
.find({_id : "574f1f979f44e7531786c80f",admin:{"$in":[Object("57508a2a3a0a919c16ace3c0")]}})
//.select(filers)
.exec(function(error, record) {
if (error) {
deferred.reject({
status:404,
message: 'Error in API',
error: error
});
} else {
if(record.length === 0){
deferred.reject({
message: 'Admin and school doesnot match',
data: record
});
}else{
deferred.resolve({
message: 'Successfully get Admin',
data: record
});
}
}
});
return deferred.promise;
}
records are return empty array.
Thanks in advance for help

The query you use works fine for me and returns object, make sure you define admin field in Schema like this:
"admin": [{type: mongoose.Schema.ObjectId }]
to avoid admin array object being string. If you compare Object("57508a2a3a0a919c16ace3c0") to "57508a2a3a0a919c16ace3c0" it will return empty array, check and replay to me, thanks.

I am not sure about how you define your School Schema, but if you are saving id in admin array as String, you don't need to change to Object in your mongoose query.
School.find({
_id: "574f1f979f44e7531786c80f",
admin: {
$in : ['57508a2a3a0a919c16ace3c0']
}
}, functin (err, record) {
...
})

Related

Firebase database collection returns empty array when trying to get all documents

I'm trying to get all documents from my database collection "posts" but I'm getting an empty array instead.
The strange thing is that I'm able to get all documents from another collection called "users" that has the same structure and using the exact same code.
I've spent days looking for an answer but I haven't been able to find the solution.
This is the request:
const db = admin.firestore();
exports.getAllPosts = (req, res) => {
db.collection('posts')
.orderBy('createdAt', 'desc')
.get()
.then(snapshot => {
let posts = [];
snapshot.forEach((doc) => {
posts.push({
id: doc.id,
body: doc.data().body,
author: doc.data().author,
createdAt: doc.data().timestamp,
voteScore: doc.data().voteScore
});
});
return res.json(posts);
})
.catch(err => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
And this is the response:
[]
This is what my current collection looks like:
Posts collection screenshot
This the response that I get when I return "snapshot":
{
"_query": {
"_firestore": {
"_settings": {
"projectId": "readable-bf7a6",
"firebaseVersion": "9.6.0",
"libName": "gccl",
"libVersion": "4.10.0 fire/9.6.0"
},
"_settingsFrozen": true,
"_serializer": {
"allowUndefined": false
},
"_projectId": "readable-bf7a6",
"registeredListenersCount": 0,
"bulkWritersCount": 0,
"_backoffSettings": {
"initialDelayMs": 100,
"maxDelayMs": 60000,
"backoffFactor": 1.3
},
"_clientPool": {
"concurrentOperationLimit": 100,
"maxIdleClients": 1,
"activeClients": {},
"failedClients": {},
"terminated": false,
"terminateDeferred": {
"promise": {}
}
}
},
"_queryOptions": {
"parentPath": {
"segments": []
},
"collectionId": "posts",
"converter": {},
"allDescendants": false,
"fieldFilters": [],
"fieldOrders": [
{
"field": {
"segments": [
"createdAt"
]
},
"direction": "DESCENDING"
}
],
"kindless": false
},
"_serializer": {
"allowUndefined": false
},
"_allowUndefined": false
},
"_readTime": {
"_seconds": 1622395245,
"_nanoseconds": 513743000
},
"_size": 0,
"_materializedDocs": null,
"_materializedChanges": null
}
Notice how the request for the collection "users" works successfully:
const db = admin.firestore();
exports.getAllUsers = (req, res) => {
db.collection('users')
.orderBy('createdAt', 'desc')
.get()
.then(snapshot => {
let users = [];
snapshot.forEach((doc) => {
let users = [];
snapshot.forEach((doc) => {
users.push({
id: doc.data().userId,
email: doc.data().email,
handle: doc.data().handle
});
});
return res.json(users);
})
.catch(err => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
And the response:
[
{
"id": "EPoHBxhQFUXbcL3TCVx1LdUG2nO2",
"email": "ruben#gmail.com"
},
{
"id": "RqEa3dEq8TSDcZYeolXafju67rB2",
"email": "user10#gmail.com"
},
{
"id": "dxveb4n2iMQej5Q14uprsKRxFp23",
"email": "user4#gmail.com",
"handle": "user4"
},
{
"id": "YQPzBPcsqlVZk9iJEuZTHKUNuVG2",
"email": "user2#gmail.com",
"handle": "user2"
},
{
"id": "CZ05BJxi3TUOpIrmBaz539OWlbC3",
"email": "user#gmail.com",
"handle": "user"
},
{
"id": "t0t83BVwt4gVgJkDv7HL1r1MaKr1",
"email": "userJose2#gmail.com",
"handle": "Jose"
}
]
This is what the users collection looks like in Firebase:
Users collection screenshot
Why is one collection failing when the other works fine and I'm using the same code? What am I missing here?
Thanks in advance and I hope I've made it as clear as possible. Please let me know if you need me to provide anything else.
Very simple my friend, your posts documents can't be ordered like this:
.orderBy('createdAt', 'desc')
Because the post documents does not have the createdAt property, but they have a timestamp property, you should use that property to order your posts like this:
.orderBy('timestamp', 'desc')
I hope that helps 👍
I am not answering directly to #Ruben Garcia Bri, but for future firebase developers who may run into the problem of getting empty documents, I also ran into the same problem, but I solved it by adding a field to the particular document I am trying to retrieve.
Sometimes the cause is because the documents you are trying to get have no field in them.
I mean that a document must have a field before the server can recognize it as an existing document.
So if you run into this problem, consider adding a field to that document before you can successfully retrieve it.

Mongoose query to check array contains element or not in mongoose query

i have records like this..
{
"photo": "default.jpg",
"roles": [
{
"_id": "5f44d77be830263684eb7914",
"name": "Test",
"__v": 0
}
],
"_id": "5f44d2f4ff04993b40684bf9",
"name": "Test User",
"email": "test#gmail.com",
"id": "5f44d2f4ff04993b40684bf9"
}
i want to weather the role user trying to delete is in use or not. for this i have write a query but it always return an empty array.
const check = await User.find({roles: {$elemMatch: {_id: req.params.id}}});
these are the queries i checked in compass but it always an array
{"roles._id":"5f44d77be830263684eb7914"}
{roles: $elemMatch: {_id: "5f44d77be830263684eb7914"}}
my User document hass roles field something like this.
roles:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"Roles",
validate: {
validator: async function(v) {
return await Roles.findById(v, (err, rec) => rec !== null)
},
message: 'Invalid Object ID'
},
required:true
}
],
IS there any way to enforce integrity constraint like if user tries to delete records which have dependencies on other records then we should not allow user to delete this record.

Cascade delete from array using Mongoose middleware remove hook

I am building a Node.js express RESTfull API using Mongodb and mongoose.
This is my schema:
var UserSchema = new mongo.Schema({
username: { type: String },
password: { type: String, min: 8 },
display_name: { type: String, min: 1 },
friends: { type: [String] }
});
UserSchema.post('remove', function(next){
console.log({ friends: this._id }); // to test if this gets reached (it does)
UserSchema.remove({ friends: this._id });
});
And this is the function that removes a User:
.delete(function(req, res) {
User.findById(req.params.user_id, function(err, user) {
if (err) {
res.status(500);
res.send(err);
} else {
if (user != null) {
user.remove();
res.json({ message: 'User successfully deleted' });
} else {
res.status(403);
res.json({ message: 'Could not find user.' });
res.send();
}
}
});
});
What I need to do is when a user is removed, his or her _id (String) should also be removed from all the other users' friends array. Hence the remove hook in the schema.
Right now the user gets deleted and the hook gets triggered, but the user _id is not removed from the friends array (tested with Postman):
[
{
"_id": "563155447e982194d02a4890",
"username": "admin",
"__v": 25,
"password": "adminpass",
"display_name": "admin",
"friends": [
"5633d1c02a8cd82f5c7c55d4"
]
},
{
"_id": "5633d1c02a8cd82f5c7c55d4",
"display_name": "Johnybruh",
"password": "donttouchjohnsstuff",
"username": "John stuff n things",
"__v": 0,
"friends": []
}
]
To this:
[
{
"_id": "563155447e982194d02a4890",
"username": "admin",
"__v": 25,
"password": "adminpass",
"display_name": "admin",
"friends": [
"5633d1c02a8cd82f5c7c55d4"
]
}
]
To try and figure it out I have looked at the Mongoosejs Documentation, but the mongoose doc example doesn't cover the remove hook. Also this stackoverflow qestion but this question seems to be about removing from other schemas.
I think i'm doing the remove in the hook wrong, but I can't seem to find the problem.
Thanks in advance!
EDIT:
I could not get the first suggestion by cmlndz to work, so I ended up fetching all the documents with arrays that contained the to-be-deleted users' id and pulling it from them one-by-one:
The delete function now contains this bit of code that does the magic:
// retrieve all documents that have this users' id in their friends lists
User.find({ friends: user._id }, function(err, friends) {
if (err) {
res.json({ warning: 'References not removed' });
} else {
// pull each reference to the deleted user one-by-one
friends.forEach(function(friend){
friend.friends.pull(user._id);
friend.save(function(err) {
if (err) {
res.json({ warning: 'Not all references removed' });
}
});
});
}
});
You could use $pull to find all documents that contain the "ID" in the "friends" array -or- find any matching document and popping the "ID" out of the array one by one.

create a new object Id in mongoDB using node js

I am using the below code to insert data to mongodb
router.post('/NewStory', function (req, res) {
var currentObject = { user: userId , story : story , _id:new ObjectID().toHexString() };
req.db.get('clnTemple').findAndModify({
query: { _id: req.body.postId },
update: { $addToSet: { Stories: currentObject } },
upsert: true
});
});
This code is working fine if i remove the _id:new ObjectID().toHexString()
What i want to achieve here is that for every new story i want a unique _id object to be attached to it
What am i doing wrong?
{
"_id": {
"$oid": "55ae24016fb73f6ac7c2d640"
},
"Name": "some name",
...... some other details
"Stories": [
{
"userId": "105304831528398207103",
"story": "some story"
},
{
"userId": "105304831528398207103",
"story": "some story"
}
]
}
This is the document model, the _id that i am trying to create is for the stories
You should not be calling .toHexString() on this as you would be getting a "string" and not an ObjectID. A string takes more space than the bytes of an ObjectId.
var async = require('async'),
mongo = require('mongodb'),
db = require('monk')('localhost/test'),
ObjectID = mongo.ObjectID;
var coll = db.get('junk');
var obj = { "_id": new ObjectID(), "name": "Bill" };
coll.findAndModify(
{ "_id": new ObjectID() },
{ "$addToSet": { "stories": obj } },
{
"upsert": true,
"new": true
},
function(err,doc) {
if (err) throw err;
console.log(doc);
}
)
So that works perfectly for me. Noting the "new" option there as well so the modified document is returned, rather than the original form of the document which is the default.
{ _id: 55c04b5b52d0ec940694f819,
stories: [ { _id: 55c04b5b52d0ec940694f818, name: 'Bill' } ] }
There is however a catch here, and that is that if you are using $addToSet and generating a new ObjectId for every item, then that new ObjectId makes everything "unique". So you would keep adding things into the "set". This may as well be $push if that is what you want to do.
So if userId and story in combination already make this "unique", then do this way instead:
coll.findAndModify(
{
"_id": docId,
"stories": {
"$not": { "$elemMatch": { "userId": userId, "story": story } }
}
},
{ "$push": {
"stories": {
"userId": userId, "story": story, "_id": new ObjectID()
}
}},
{
"new": true
},
function(err,doc) {
if (err) throw err;
console.log(doc);
}
)
So test for the presence of the unique elements in the array, and where they do not exist then append them to the array. Also noting there that you cannot do an "inequality match" on the array element while mixing with "upserts". Your test to "upsert" the document should be on the primary "_id" value only. Managing array entries and document "upserts" need to be in separate update operations. Do not try an mix the two, otherwise you will end up creating new documents when you did not intend to.
By the way, you can generate an ObjectID just using monk.
var db = monk(credentials.database);
var ObjectID = db.helper.id.ObjectID
console.log(ObjectID()) // generates an ObjectID

Issue with a simple mongo/monk findAndModify query

Just a note I am fairly new to mongo and more notably very new to using node/js.
I'm trying to write a query to insert new documents or update already existing documents in my collection.
The proposed structure of the collection is:
{ _id: xxxxxxx, ip: "xxx.xxx.xxx.xxx:xxxxxx", date: "xx-xx-xx xxxx" }
Note that my intention is a store an fixed length int for the _id rather than the internal ObjectId (is this possible/considered bad practice?). The int is guaranteed to be unique and comes from another source.
var monk = require('monk');
var db = monk('localhost:27017/cgo_schedule');
var insertDocuments = function(db, match) {
var db = db;
var collection = db.get('cgo_schedule');
collection.findAndModify(
{
"query": { "_id": match.matchId },
"update": { "$set": {
"ip": match.ip,
"date": match.date
},
"$setOnInsert": {
"_id": match.matchId,
}},
"options": { "new": true, "upsert": true }
},
function(err,doc) {
if (err) throw err;
console.log( doc );
}
);
}
This doesn't work at all however. It doesn't insert anything to the database, but it also gives no errors, so I have no idea what I'm doing wrong.
The output (for console.log (doc)) is null.
What am I doing wrong?
The Monk docs aren't much help, but according to the source code, the options object must be provided as a separate parameter.
So your call should look like this instead:
collection.findAndModify(
{
"query": { "_id": match.matchId },
"update": {
"$set": {
"ip": match.ip,
"date": match.date
}
}
},
{ "new": true, "upsert": true },
function(err,doc) {
if (err) throw err;
console.log( doc );
}
);
Note that I removed the $setOnInsert part as the _id is always included on insert with an upsert.

Resources