How to know which array element is present in my database array? - arrays

I want to write a query in mongoDB where I want to find which elements of my array are present in database array 'upvotes' my query is given below
userupvotesmodel.findOne({mobile_no: "1234567890", upvotes : { $in : ["aa", "bdnvh", "563fa4408d88ea6c13c7abba", "djfufhgj", "5625bd9dbe545d2412d4ae62", "fjjshddhjfn", "djfhudh", "jfhshnffj", "sjdhfkskajdk"] } }, function(err, docs) {
if (err) {
console.log('Error Finding query results');
console.log(err);
res.json({success: 0, message : err});
return next(err);
} else {
if (docs) {
console.log('2 mins', currentdate.getMinutes());
console.log('2 secs', currentdate.getSeconds());
console.log('docs', docs);
}
}
});
Now for query above if any single value of my array is present in database then it sends whole upvotes array but I am not able to find out which elements were present for e.g "aa", "bdnvh" etc in database how can I write a query to know which elements are present in the database.
I want to find this in one query by querying for every single element; I know I can do this but I want to do this in any possible single mongoDB query.

I think you don't need to worry about the query and you can just use java script instead. Just iterate through the docs.upvotes array and compare its values with the array you provided.
var my_array = ["aa", "bdnvh", "563fa4408d88ea6c13c7abba", "djfufhgj", "5625bd9dbe545d2412d4ae62", "fjjshddhjfn", "djfhudh", "jfhshnffj", "sjdhfkskajdk"];
// ... your code
// inside of if(docs) statement
var matched_elements = [];
docs.upvotes.forEach(function(element, index, array) {
for (var i = 0; i < my_array.length; i++) {
if (my_array[i] == element) {
matched_elements.push(element);
}
}
});
console.log(matched_elements);

You could use the aggregation framework. First $unwind your upvotes array. Then $match on elements that are in the array provided by you. Than $group it back on _id(or whatever you want) creating "matched_elements" array with $addToSet or $push. The returned documents will have only upvotes elements (in "matched_elements array) that are also in your array.
var my_array = ["aa", "bdnvh", "563fa4408d88ea6c13c7abba", "djfufhgj", "5625bd9dbe545d2412d4ae62", "fjjshddhjfn", "djfhudh", "jfhshnffj", "sjdhfkskajdk"];
db.collection.aggregate( [
{ "$unwind" : "$upvotes" },
{ "$match": { "upvotes": {"$in": my_array} } },
{ "$group" : { "_id":"$_id","matched_elements":{ "$addToSet": "$upvotes" }}}
] );

Related

Query model with array in mongodb

I am new in node and MongoDB.
I am trying to query a model with an array.
The array looks like this
var grArr = [ '5aabc39a3d88101e4b52c861', '5ac3a1fe83d45353bc6a995c' ]
And the query is
Group.find().where({ _id: { $in: grArr }}).exec(function(err,gdoc){
if(err)
{
callback({err:err,message:"Error looking up company"});
}
else
{
console.log(gdoc.companies); //Gives undefined
callback(null,gdoc.companies);
}
});
The query returns undefined.
Any help is highly appreciated.
There is 2 ways to perform a query with mongoose, and it seems to me that you're mixing both of them.
Find should be called with your query as parameter:
And you get something like
Group.find({ _id: { $in: grArr }}, function(err,gdoc){
if(err) {
callback({err: err, message:"Error looking up company"});
}
else {
console.log(gdoc); //Should print all the matching documents since gdoc is an array
callback(null, gdoc.map(doc => doc.companies); //returns every companies of every document
}
});
The Query API of mongoose
This time you can call Find with no parameters and chain the where statement like this
Group.find({}).where('_id').in(grArr).exec(callback)
find() passed array to the callback function. See documentation https://mongoosejs.com/docs/api.html#model_Model.find
gdoc is array. Edit your code like this:
...
callback(null, gdoc[0].companies);
...
Try this,
Group.find({ _id: { $in:arr }).lean().exec().then((result) => {
}, (err) => {
});

How to check if an array field matches an array query mongodb

I have an issue fetching data from a MongoDB database that contains an array and also retrieve elements that are not in the query array.
The database is structured like below:
{
"name": "James",
"visitedPlaces": ['Germany', "Scotland"]
},
{
"name": "John",
"visitedPlaces": ['India', "Russia"]
}
I want to query the VisitedPlaces to return only return people that have not visited Russia and India.
NOTE: I am querying the database with another array.
db.Profile.find(
{ VisitedPlaces: { $elemMatch: { $nin: ["India", "Russia"] } } }
)
You must use $all to query an array that contains both the another array:
db.Profile.find(
{ visitedPlaces: {$not:{$all:["India", "Russia"]}}}
)

Remove oldest N elements from document array

I have a document in my mongodb that contains a very large array (about 10k items). I'm trying to only keep the latest 1k in the array (and so remove the first 9k elements). The document looks something like this:
{
"_id" : 'fakeid64',
"Dropper" : [
{
"md5" : "fakemd5-1"
},
{
"md5" : "fakemd5-2"
},
...,
{
"md5": "fakemd5-10000"
}
]
}
How do I accomplish that?
The correct operation to do here actually involves the $push operator using the $each and $slice modifiers. The usage may initially appear counter-intuitive that you would use $push to "remove" items from an array, but the actual use case is clear when you see the intended operation.
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [], "$slice": -1000 } }
)
You can in fact just run for your whole collection as:
db.collection.update(
{ },
{ "$push": { "Dropper": { "$each": [], "$slice": -1000 } },
{ "multi": true }
)
What happens here is that the modifier for $each takes an array of items to "add" in the $push operation, which in this case we leave empty since we do not actually want to add anything. The $slice modifier given a "negative" value is actually saying to keep the "last n" elements present in the array as the update is performed, which is exactly what you are asking.
The general "intended" case is to use $slice when adding new elements to "maintain" the array at a "maximum" given length, which in this case would be 1000. So you would generally use in tandem with actually "adding" new items like this:
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [{ "md5": "fakemd5-newEntry"}], "$slice": -1000 } }
)
This would append the new item(s) provided in $each whilst also removing any items from the "start" of the array where the total length given the addition was greater than 1000.
It is stated incorrectly elsewhere that you would use $pullAll with a supplied list of the array content already existing in the document, but the operation is actually two requests to the database.
The misconception being that the request is sent as "one", but it actually is not and is basically interpreted as the longer form ( with correct usage of .slice() ):
var md5s = db.collection.findOne({ "_id": "fakeid64" }).Dropper.slice(-1000);
db.collection.update(
{ "_id": "fakeid64" },
{ "$pullAll": { "Dropper": md5s } }
)
So you can see that this is not very efficient and is in fact quite dangerous when you consider that the state of the array within the document "could" possibly change in between the "read" of the array content and the actual "write" operation on update since they occur separately.
This is why MongoDB has atomic operators for $push with $slice as is demonstrated. Since it is not only more efficient, but also takes into consideration the actual "state" of the document being modified at the time the actual modification occurs.
you can use $pullAll operator
suppose you use python/pymongo driver:
yourcollection.update_one(
{'_id': fakeid64},
{'$pullAll': {'Dropper': yourcollection.find_one({'_id': 'fakeid64'})['Dropper'][:9000]}}
)
or in mongo shell:
db.yourcollection.update(
{ _id: 'fakeid64'},
{$pullAll: {'Dropper': db.yourcollection.findOne({'_id' : 'fakeid64'})['Dropper'].slice(0,9000)}}
)
(*) having saying that it would be much better if you didn't allow your document(s) to grow this much in first place
This is just a representation of query. Basically you can unwind with limit and skip, then use cursor foreach to remove the items like below :
db.your_collection.aggregate([
{ $match : { _id : 'fakeid64' } },
{ $unwind : "$Dropper"},
{ $skip : 1000},
{ $limit : 9000}
]).forEach(function(doc){
db.your_collection.update({ _id : doc._id}, { $pull : { Dropper : doc.Dropper} });
});
from mongo docs
db.students.update(
{ _id: 1 },
{
$push: {
scores: {
$each: [ { attempt: 3, score: 7 }, { attempt: 4, score: 4 } ],
$sort: { score: 1 },
$slice: -3
}
}
}
)
The following update uses the $push operator with:
the $each modifier to append to the array 2 new elements,
the $sort modifier to order the elements by ascending (1) score, and
the $slice modifier to keep the last 3 elements of the ordered array.

MongoDB find all not in this array

I'm trying to find all users except for a few, like this:
// get special user IDs
var special = db.special.find({}, { _id: 1 }).toArray();
// get all users except for the special ones
var users = db.users.find({_id: {$nin: special}});
This doesn't work because the array that I'm passing to $nin is not and array of ObjectId but an array of { _id: ObjectId() }
Variable special looks like this after the first query:
[ { _id: ObjectId(###) }, { _id: ObjectId(###) } ]
But $nin in the second query needs this:
[ ObjectId(###), ObjectId(###) ]
How can I get just the ObjectId() in an array from the first query so that I can use them in the second query?
Or, is there a better way of achieving what I'm trying to do?
Use the cursor.map() method returned by the find() function to transform the list of { _id: ObjectId(###) } documents to an array of ObjectId's as in the following
var special = db.special.find({}, { _id: 1 }).map(function(doc){
return doc._id;
});
Another approach you can consider is using the $lookup operator in the aggregation framework to do a "left outer join" on the special collection and filtering the documents on the new "joined" array field. The filter should match on documents whose array field is empty.
The following example demonstrates this:
db.users.aggregate([
{
"$lookup": {
"from": "special",
"localField": "_id",
"foreignField": "_id",
"as": "specialUsers" // <-- this will produce an arry of "joined" docs
}
},
{ "$match": { "specialUsers.0": { "$exists": false } } } // <-- match on empty array
])

MongoDB - Querying based on the value of a property of an array of objects

Brand new to MongoDB. I'm having difficulty querying by a property of an object nested in an array.
I have the following data structure:
{
"sales":[
{
"item":1234,
"seller":"SellerA",
"buyer":"BuyerA"
},
{
"item":5678,
"seller":"SellerB",
"buyer":"SellerB"
},
{
"item":1122,
"seller":"SellerA",
"buyer":"BuyerA"
},
{
"item":1199,
"seller":"SellerB",
"buyer":"SellerB"
}
]
}
I have other properties at the same level as the "sales" array, but I've simplified for the example.
I am attempting to pull every sales document which has a buyer value of "BuyerB."
I've tried the following:
db.data.find({"sales": {$elemMatch: {buyer: "BuyerB"}}})
db.data.find({"sales.buyer": "BuyerB"}})
These queries run, but return every row of data and not just the ones that have a buyer value of "BuyerB"
I know there has to be a simple answer, but what my searches have turned up is what I've already tried without success.
As you may return more than one element from an array and .find() cannot do this, you can try aggregate such as:
db.c.aggregate({
$match : {
"sales.buyer" : "BuyerB"
}
}, {
$unwind : "$sales"
}, {
$match : {
"sales.buyer" : "BuyerB"
}
}, {
$group : {
_id : "$_id",
sales : {
$push : "$sales"
}
}
});

Resources