Return an array from Model.findOne? - mongodb

I have a query which retuns an array of documents as a promise (.exec).
Further I have a (promised) function which also returns an array. Both are combined in a Promise.all.
Now I want to move the .find to a .findOne to speed up the filter. But with findOne I would get no array back. So I decided to use .find().limit(1)
My question is if this is a valid approach, instead of the use of .findOne and if not: Is there a simple way to return the result of findOne as an array? Maybe with .lean ?
var query = Model.find({ $and: [ { _id: id },
{ $or: [ { owner: userID },
{ isPublic: true } ]}
]}).limit(1);
Promise.all([query.exec(), this._sources(user)]).then((doc: Array<any>) => {....}

findOne returns an object, not an array. You can create an array with the result like this: return [obj]. I'm not sure but you can try this one
var queryResult = Model.findOne({ $and: [ { _id: id },
{ $or: [ { owner: userID },{ isPublic: true } ]}]})
.exec(function(err, data){
if(err) return [];
return [data];
});
Promise.all([queryResult, this._sources(user)]).then

Related

Mongoose Query with array of object

I want to query using _id in array of object.
const members = [
{ _id: 60fb6f2859fd441f38e21172 },
{ _id: 60fb70a059fd441f38e21175 },
{ _id: 60fb6d9459fd441f38e2116c }
]
I know if it's an simple array, we can use $in operator. Please help how to query using above array.
const files = await File.find({ _id: { $in: members._id } });

Update a document and upsert a subdocument in a single query

How do I update an item in the parent document and upsert a subdocument in a single query?
This is my example schema.
const ExampleSchema = new Schema({
user_count: {
type: String,
default: 0
},
users: [
{
id: {
type: Schema.Types.ObjectId,
ref: "users",
unique: true
},
action: {
type: Boolean
}
}
],
});
I am trying to add +1 to user_count and upsert a document to the users array in a single query.
const result = await Example.updateOne(
{
_id: id,
},
{
$set: {
"user_count": user_count++,
"users.$.id": req.user.id,
"users.$.action": true
}
},
{ upsert: true }
);
I have tried the above code, but got the following error.
[0] 'The positional operator did not find the match needed from the query.',
[0] [Symbol(mongoErrorContextSymbol)]: {} }
I'm not familiar with mongoose, so I will take for granted that "user_count": user_count++ works.
For the rest, there are two things that won't work:
the $ operator in "users.$.id": req.user.id, is known as the positional operator, and that's not what you want, it's used to update a specific element in an array. Further reading here: https://docs.mongodb.com/manual/reference/operator/update/positional/
the upsert is about inserting a full document if the update does not match anything in the collection. In your case you just want to push an element in the array right?
In this case I guess something like this might work:
const result = await Example.updateOne(
{
_id: id,
},
{
$set: {
"user_count": user_count++
},
$addToSet: {
"users": {
"id": req.user.id,
"action": true
}
}
}
);
Please note that $push might also do the trick instead of $addToSet. But $addToSet takes care of keeping stuff unique in your array.
db.collection.findOneAndUpdate({_id: id}, {$set: {"user_count": user_count++},$addToSet: {"users": {"id": req.user.id,"action": true}}}, {returnOriginal:false}, (err, doc) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
});

How to perform aggregate query with where condition

I have this MongoDB query:
var array=[]; //some string values
collection.aggregate(
{ $match: { '_id': { $in : array } } }
)
But this is not returning any results. How do I perform this?
As noted in the comments, your array variable is an array of hex string values ex :["57f36e94517f72bc09ee761e"] and for mongo shell, you need to first cast those string values to ObjectIds. Use the JavaScript map()
method to accomplish the casting in a list.
For example:
mongo shell
var array = ["585808969e39db5196444c07", "585808969e39db5196444c06"];
var ids = array.map(function(id){ return ObjectId(id); });
which you can then query using the aggregate function as in the following
db.collection.aggregate([
{ "$match": { "_id": { "$in" : ids } } }
])
The above is essentially the same as
db.collection.find({ "_id": { "$in": ids } })
Node.js
var {ObjectId} = require('mongodb'); // or ObjectID
var ids = array.map(id => ObjectId.isValid(id) ? new ObjectId(id) : null;);

How can I find all records where an id is in one array, or another id is in another array?

I need to perform a query that returns all results where an id, or array of ids in an array of ids AND another id, or array of ids, is in another array of ids. Perhaps an example will better explain what I'm trying to do:
Schema:
var somethingSchema = mongoose.Schema({
space_id : String,
title : String,
created : {
type: Date,
default: Date.now
},
visibility : {
groups : [{
type : String,
ref : 'Groups'
}],
users : [{
type : String,
ref : 'User'
}]
}
});
Query:
something.find({
space_id: req.user.space_id,
$and: [
{ $or: [{ "visibility.groups": { $in: groups } }] },
{ $or: [{ "visibility.users": { $in: users } }] }
]
}, function (err, data) {
return res.json(data);
});
In this example, both groups and users are arrays of ids. The query above isn't working. It always returns an empty array. What am I doing wrong?
You should be including all clauses to OR together in a single $or array:
something.find({
space_id: req.user.space_id,
$or: [{ "visibility.groups": { $in: groups } },
{ "visibility.users": { $in: users } }]
}, function (err, data) {
return res.json(data);
});
Which translates to: find all docs with a matching space_id AND that have a visibility.groups value in groups OR a visibility.users value in users.

Update multiple documents by id set. Mongoose

I wonder if mongoose has some method to update multiple documents by id set. For example:
for (var i = 0, l = ids.length; i < l; i++) {
Element.update({'_id': ids[i]}, {'visibility': visibility} ,function(err, records){
if (err) {
return false;
} else {
return true;
};
});
};
What i want to know, that if mongoose can do something like this:
Element.update({'_id': ids}, {'visibility': visibility}, {multi: true} ,function(err, records){
if (err) {
return false;
}
});
where ids is an array of ids, like ['id1', 'id2', 'id3'] - sample array.
Same question for find.
Most probably yes. And it is called using $in operator in mongodb query for update.
db.Element.update(
{ _id: { $in: ['id1', 'id2', 'id3'] } },
{ $set: { visibility : yourvisibility } },
{multi: true}
)
All you need is to find how to implement $in in mongoose.
in updateMany function no need of { multi: true }
db.collectionName.updateMany(
{
_id:
{
$in:
[
ObjectId("your object id"),
ObjectId("your object id")
]
}
},
{
$inc: { quantity: 100 }
})
I want to add one more point, you can use $in to fetch multiple document
db.collectionName.find(
{
_id:
{
$in:
[
ObjectId("your object id"),
ObjectId("your object id")
]
}
})
Updates all documents that match the specified filter for a collection.
let ids = ["kwwe232244h3j44jg3h4", "23h2u32g2h3b3hbh", "fhfu3h4h34u35"];
let visibility = true;
Element.updateMany({_id: {$in: ids}},
{ $set: { visibility } },
{multi: true} ,
function(err, records){
if (err) {
return false;
}
});
know more