Mongoose & MongoDB, find() except one that contains one property - javascript

Im looking for a condition in Mongoose that allows me to find all the users except the ones that haves the role 'Admin':2000. Mind that the admin users also has anothers roles, like "User" and "Editor", like this:
{
"name": "John Doe Admin",
"roles": {
"Admin": 555,
"Editor": 556,
"User": 557
}
}

In the comments is the answer:
.find({ 'roles.Admin': { $ne: 2000 } })

Related

MongoDB find() not filtering by string

I am currently trying to retrieve certain objects from a mongoDB database using Mongoose.
For some reason I cant filter by the field "provider" that i assigned to my object, but i can filter by the "date" field.
This works perfectly:
const logs = await ActionLog.find({ date:{ $gt: initialDate, $lt: finishDate}});
if(logs.length == 0){
res.status(204);
res.json({message:"No matches for this search"});
}else
res.send(logs);
but this doesn't, it just brings me all of the elements saved:
const logs = await ActionLog.find({ provider:"example" } );
Some of the elements have the field "provider" and some of them don't, but none of them has provider:"example"
[
{
"_id": "6374768bd302cd09838d4c67",
"module": "event approval",
"date": "2022-11-16T05:35:07.252Z",
"__v": 0
},
{
"_id": "637476aad302cd09838d4c69",
"module": "event update",
"date": "2022-11-16T05:35:38.798Z",
"__v": 0
},
{
"_id": "6374768bd302cd09838d4c11",
"module": "sale",
"provider": "prueba",
"date": "2022-11-20T05:35:07.252Z",
"__v": 0
}
]
The problem was my model didn't have "provider" in it.
Blockquote s "provider" on your mongoose model? I havent use mongoose in a while but I think I recall that for it to query on a field it must actually be on your model. I might be remembering this wrong though. –
Sello Mkantjwa
Once i added "provider" to the model it worked.

Create a firebase style permission hierarchy in mongoDB

New to MongoDB, and working with NodeJS's mongodb package, I am trying to retrieve and update items based on a user's permission levels which are also stored in a collection.
I understand how to fetch all items:
const collection = db.collection('events');
// Find some documents
collection.find({}).toArray(function(err, docs) {
assert.equal(err, null);
console.log("Found the following records");
console.log(docs)
callback(docs);
});
But I wonder whether, given the following data structure:
{
events: {
1: {
id: 1,
name: "first event",
},
2: {
id: 2,
name: "2nd event",
},
3: {
id: 3,
name: "3rd event",
},
},
permissions: {
events: {
1: {
user1: "read",
user2: "write",
},
2: {
user2: "write",
},
3: {
user1: "readwrite",
user2: "write",
},
},
},
}
and given you are logged in as User1, the above fetch code can fetch only the relevant events which user1 has read access to according to the permissions specified?
For CRUDS such as updates, deletes and inserts, I can run a separate query and see whether the user has the needed access. However, get queries are common and IMHO should be straightforward so I wonder how this filtering can be done elegantly?
First of all, I would simplify your data model, since there is a thing that well might bite you in your back later down the road. You should not use values as keys, as you did in the event documents. Clearly, those are arrays, and the array elements already have an id they can be referenced by.
Furthermore, your data model (and subsequently my derived one) is only good for a couple of thousand events, as there is a 16MB limit on documents. In order to mitigate this, I will show you an updated data model and how to deal with it, too.
One document for events
Data model
Here is my updated data model. We basically got rid of the unnecessary values posing as keys.
{
"events": [{
"id": 1,
"name": "first event",
},
{
"id": 2,
"name": "2nd event",
},
{
"id": 3,
"name": "3rd event",
}
],
"permissions": [{
"event": 1,
"perms": [{
"user": "user1",
"permission": "read",
},
{
"user": "user2",
"permission": "write"
}
]
},
{
"event": 2,
"perms": [{
"user": "user2",
"permission": "write"
}]
},
{
"event": 3,
"perms": [{
"user": "user1",
"permission": "readwrite"
},
{
"user": "user2",
"permission": "write"
},
]
}
],
}
Which still gives you the possibility to search for specific events via db.events.find({"events.id":1},{"events.$":1}). This, of course works for each and every other property of an event.
Permission check
The basic question of wether a user has a permission to do a certain operation on a specific document can be rephrased as
Get me all documents with the properties I am interested in AND for which user Y has the permission to do Z.
This translates to a rather simple query:
db.events.find({
// The event we want...
"events.id": 1,
// ...shall be returned provided the following conditions are met
"permissions": {
$elemMatch: {
// The permissions for event with id 1...
"event": 1,
"perms": {
$elemMatch: {
// ...allow the user in question...
"user": "user1",
// ... to read said event.
"permission": "read"
}
}
}
}
}, {
// Subsequently, we return all matching events in all documents...
"events.$": 1
})
What we use here is that query conditions are evaluated as logical AND. If the user does not have the permission we requested ("read" in this example), no document is returned.
One document per event
Data model
However, as said, there is a 16MB size limit on MongoDB documents. So if you have a lot of events, or even when you are not really sure about the number of events you might have, we should approach the problem from a different (and even simpler) angle: One document per event. The data model gets stupidly simple:
// db.events.insertMany([
{
"_id": 1,
"name": "first event",
"permissions":[
{
"user":"user1",
"permission": "read"
},
{
"user":"user2",
"permission":"write"
}
]
},
{
"_id":2,
"name": "2nd event",
"permissions":[
{
"user": "user2",
"permission": "write"
}
]
},
{
"_id":3,
"name": "3rd event",
"permissions":[
{
"user": "user1",
"permission": "readwrite"
},
{
"user": "user2",
"permission": "write"
},
]
}
// ])
Permission check
Now, let us say we want to check wether user1 can actually read (which includes readwrite) event 3 and if so, return it. Becomes even less complicated than before:
db.events.find({
// The event we want...
"_id": 3,
// ...in case...
"permissions": {
$elemMatch: {
// ... user1...
"user": "user1",
// ..has either the permission...
$or: [{
// ...to read or...
"permission": "read"
}, {
// ... to readwrite.
"permission": "readwrite"
}]
}
}
}, {
// Either way, do not return the permissions.
permissions: 0
})
Conclusion
Regardless of which data model of the two you will choose, you can use the above queries as the query part of your update statements:
db.events.update(<queryFromAbove>,{[...]})
Needless to say, I would strongly suggest to use the "one-document-per-event" approach.
However, there are two things you need to keep in mind.
If something goes wrong, you need to do extra queries to find out what went wrong. The event might either not exist altogether, or the user might not have the necessary permission to execute the query/update. However, since this should be the exception, I personally could live with that.
The other thing to keep in mind is that you need to make sure that a user can never, ever change the permissions array. For rather obvious reasons.

How to update all of an object's properties with spread syntax with Mongoose and Node

Thank you in advance, Im really stuck on this!
I have a User object in the database like such:
{
"_id": {
"$oid": "5a83470e722c1e00142e2216"
},
"first_name": "Test",
"last_name": "User",
"password": "$2a$10$FdsPkcjeLOpwfCRCHOSg6eqVDrDlbpi330tyG/Z.XPl3dKzX5K3s.",
"email": "test.com",
"role": 3
}
So I'm calling a function that is supposed to update an object, like a user just edited their profile.
This is the body of my request:
{
"userID": "5a83470e722c1e00142e2216",
"employee": {
"first_name": "TestNEW",
"last_name": "UserNEW",
"password": "$2a$10$FdsPkcjeLOpwfCRCHOSg6eqVDrDlbpi330tyG/Z.XPl3dKzX5K3s.",
"email": "NEWUSER.com",
"role": 3
}
}
When I update the object, I want to $set or $update the entire user object, except for the _id. So, Im using this:
User.findOneAndUpdate({ _id: new ObjectID(req.body.userID)},
{ $set: { ...req.body.employee } }, function(err, user)...etc etc
But that doesnt work of course! So Im wondering how I can $set or $update (not sure which) all of the properties on the Object except for its _id, without using brute force like { $set: { first_name: req.body.employee.firstName, last_name: req.body.employee.lastName, ...etc etc etc } }
I know this way works, but I want to do it in a cooler way of course, can anybody help? Thank you!

Delete an object in Scope

This question might not even be related to angularjs and the solution could be plain old js or jquery. But that is what i what to find out.
I want to implement a delete functionality for a particular user and i am wondering if there is a easier way to do this in angularjs or should it be plain old JS?
i have a fairly complex object for eg (going up to 4 levels):
{
"Department": [
{
"Name": "Accounting",
"users": [
{
"id": "1",
"firstName": "John",
"lastName": "Doe",
"age": 23
},
{
"id": "2",
"firstName": "Mary",
"lastName": "Smith",
"age": 32
}
]
},
{
"Name": "Sales",
"users": [
{
"id": "3",
"firstName": "Sally",
"lastName": "Green",
"age": 27
},
{
"id": "4",
"firstName": "Jim",
"lastName": "Galley",
"age": 41
}
]
}
]
}
this is displayed in a ng-repeat where we should Department and username. If I want to delete a particular user i make an api call and on success of it, I want to delete that object. so i have a js method like this
function DeleteUser(user) {
$.each(ctrl.UserData, function(index, value) {
var filteredPeople = value.filter((item) => item.id !== user.id);
});
The question I have is, if i want to delete this object is there any easier way to delete from model since i have the object here or i have to do the classic jquery way of using like $.grep or filter to iterate through each object and match by id and then delete it?
Presumably, you're iterating over the departments (accounting, sales) in your template, and then over the users in that department.
So you could have, in your template:
<button ng-click="deleteUser(user, department)">...</button>
And the method could thus be as simple as
$scope.deleteUser = function(user, department) {
// delete user from backend, then
department.users.splice(departments.users.indexOf(user), 1);
}
If you really don't want to pass the department, then loop over the departments, and use the above if departments.users.indexOf(user) returns a value that is >= 0.

Ember JS + Ember Data: Sideloading doesn't work with string ids

I'm using ember rc3 and ember-data 12 (sha e324f0e) (basically the files recommended in the guides). I have 2 models set up as follows:
App.User = DS.Model.extend({
username: DS.attr('string'),
playerType: DS.attr('string'),
cars: DS.hasMany('App.Car')
})
App.Car = DS.Model.extend({
name: DS.attr('string'),
thumb: DS.attr('string'),
user: DS.belongsTo('App.User')
})
The json returned is
{
"cars": [
{
"id": "50ace47234fa7557403e7f02",
"name": "Dodge Charger SRT8",
"thumb": "/static/images/carthumbs/18331.png",
"user_id": "502a754b34fa75280c000a7e"
},
{
"id": "508668cc34fa753b78784ca2",
"name": "BMW M3 Coup\u00e9",
"thumb": "/static/images/carthumbs/23250.png",
"user_id": "502a754b34fa75280c000a7e"
},
{
"id": "50c7545334fa750ab8cb3ac2",
"name": "BMW Z4 M Coup\u00e9",
"thumb": "/static/images/carthumbs/7618.png",
"user_id": "502a754b34fa75280c000a7e"
},
{
"id": "50adf64c34fa750bb036121e",
"name": "2013 Ford Shelby GT500\u2122",
"thumb": "/static/images/carthumbs/24824.png",
"user_id": "502a754b34fa75280c000a7e"
}
],
"user": {
"id": "502a754b34fa75280c000a7e",
"car_ids": [
"50ace47234fa7557403e7f02",
"508668cc34fa753b78784ca2",
"50c7545334fa750ab8cb3ac2",
"50adf64c34fa750bb036121e"
],
"player_type": "Standard Player",
"username": "WillMckenzie"
}
}
Everything seems to load fine if I call App.User.find("502a754b34fa75280c000a7e"), but when I try and access the cars property on the user it triggers a second http request to the cars api route. It was my understanding that this shouldn't be necessary, and if I change the ids to basic ints, it doesn't. As I'm using Mongo as my DB my ids have to be in this string format.
Any suggestions as to what I'm doing wrong?
Cheers
Will
Here's the answer so people don't have to dig through the comments:
"I had one car id listed that wasn't in the list of cars returned. They're grabbed slightly differently and I obviously had a bad record in there. This meant it always thought it needed to reload that record so would keep requesting. Obviously when I was faking the integer ids it was masking this." - OiNutter

Categories