Skip fields on collection.find() not working - node.js

I'm developing a report system in Node.JS and MongoDB
I'm trying to make a query to get some datas from the MongoDB, but the query don't specify all the fields that the collection have
(example, in the query I'm asking for the field typ, event and date, but in the collection I have more than 10 fields).
db.collection('logs').find({
system: {
type: query.logType,
event: query.event,
date: query.date
}
}).toArray(function (err, document) {
if (err) throw err;
console.log(document);
});
This way, it doesn't return anything, but when I specify all the fields that the collection have, the query works.
Is there any way to use RegEx or skip the other not-needed fields on the query?

you can use map and select properties in that function
let tmp = [{id:1,name:"aaa"},{id:2,name:"bbb"}].map((item)=>{
// your can make new object here
return {name: item.name};
});
console.log(tmp);

Related

Mongodb multiple conditions

New to MongoDB and express interactions. I'm trying to query the database based on URL parameters, essentially I want to grab URL parameters then add them to an object if they exist to use when querying the database. I set up my express path and understand that the find() method accepts an object, when I hard code the key-value pair like below I get the correct data but when I set an object called filter with the same key-value pairs as the hard-coded example and uncomment filter and comment state and type then pass it to the find method I get an empty array. Whats the reason for this and what's the best way to achieve this?
app.get('/query', function (req, res) {
var filter = {
state: "florida",
type: "red"
}
db.collection('tickets').find({
//filter
state:"florida",
type:"red"
})
.toArray(function (err, documents) {
// Here is where we decide what to do with the query results
if (err)
throw err
res.send(documents)
})
});
The find method accepts a query object as the first parameter, the query object is your filter object yourself. therefore, you should do it like this:
db.collection('tickets').find(filter)
.toArray(function (err, documents) {
// Here is where we decide what to do with the query results
if (err)
throw err
res.send(documents)
})

mongoDB - Text Search in multiple fields using node.js

I am trying to using Node.JS connected to a MongoDB database (all hosted on heroku, so using MongoLab plugin) to perform a text search. I would like to search certain fields (strings or arrays of strings, however I can change them to all strings need be) of my documents for a variable keyword.
What the code below hopefully would do is search either the 'title' field or 'ingredients' field for the keyword variable, and then return those results.
I am dubious of the ensureIndex lines (tried both ensureIndex and createIndex) because removing them does not change the functionality of the program.
Any help would be appreciated!
app.get('/searchtitle', function(request, response) {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "X-Requested-With");
response.set('Content-Type', 'application/json');
var type = request.query.type;
var keyword = request.query.keyword;
if (type == 'title') {
db.collection('Test_Recipes').ensureIndex( { title: "text" } );
db.collection('Test_Recipes').find({
$text: {$search: keyword }
}).toArray(function(err, results){
response.send(JSON.stringify(results)) });
}
else {
console.log("in else case: type is "
+ type + " and keyword is " +keyword);
db.collection('Test_Recipes').ensureIndex({ingredients :"text"});
db.collection('Test_Recipes').find({
ingredients: {$elemMatch: keyword } })
.toArray(function(err, results){
response.send(JSON.stringify(results)) });
}
}
Indexes, as in any databases, need to be created only once, when the collection is first created. Index creation is a costly operation and a blocking operation.
As of mongoDB 3.0 there is no difference between the methods createIndex() and ensureIndex(), and either of them should be used to create indexes on the collection, only once, in the server side, when the collection is created and be modified only when required.
To index both the title and the ingredients fields, you need to create index on the collection as:
db.collection.createIndex({"ingredients":"text","title":"text"})
This would ensure that both the fields are indexed, when the document is inserted.
I am dubious of the ensureIndex lines (tried both ensureIndex and
createIndex) because removing them does not change the functionality
of the program. Any help would be appreciated!
This is because, how the createIndex() operation behaves. Only the first call to this method succeeds and others are simply ignored, if the indexes are created on the same field(s) again.
Then just querying, as below would query for the keyword in both the title and ingredients fields.
var type = request.query.type;
var keyword = request.query.keyword;
db.collection('Test_Recipes').find({
$text: {$search: keyword }
}).toArray(function(err, results){
response.send(JSON.stringify(results))
});

Mongoose how do I query for multiple documents, save if not found, and return id?

I am trying to create a query to satisfy the following conditions:
Search for the documents with specified name's' in a collection.
If the documents with specified names do not exist in the collection, create new documents.
Return ._id of the documents either they are newly saved or not.
How can I achieve this without using a for loop?
var tagArr = req.body.tags.join()
Tag.find({tagName: {$in: tagArr}}, function(err, docs){
// find the tag._ids by tagNames
// if tag not found, create a tag
// return old and new tag_ids with the tagNames
}
You should use findOneAndUpdate() with upsert option set to true:
var tagArr = req.body.tags.join();
var idArr = [];
tagArr.forEach(function(tag){
Tag.findOneAndUpdate(
{tagName: tag},
{tagName: tag},
{upsert: true},
function(err, doc){
if(!err)
idArr.push(doc._id);
}
});
If there is no tag with specified name, findOneAndUpdate() will create new one with that name and return it, so you can have its _id.

Updating array within mongodb record with mongoose

What is the best way to update a value within an array saved in a mongodb record? Currently, I'm trying it this way:
Record.find({ 'owner': owner}, {}, {sort: { date: -1 }}, function(err, record){
if(!err){
for (var i = 0; i < record[0].array.length; i++){
record[0].array[i].score = 0;
record[0].array[i].changed = true;
record[0].save();
}
}
});
And the schema looks like this:
var recordSchema = mongoose.Schema({
owner: {type: String},
date: {type: Date, default: Date.now},
array: mongoose.Schema.Types.Mixed
});
Right now, I can see that the array updates, I get no error in saving, but when I query the database again, the array hasn't been updated.
It would help if you explained your intent here as naming a property "array" conveys nothing about its purpose. I guess from your code you hope to go and set the score of each item there to zero. Note your save is currently being ignored because you can only save top-level mongoose documents, not nested documents.
Certain find-and-modify operations on arrays can be done with a single database command using the Array Update Operators like $push, $addToSet, etc. However I don't see any operators that can directly make your desired change in a single operation. Thus I think you need to find your record, alter the array date, and save it. (Note findOne is a convenience function you can use if you only care about the first match, which seems to be the case for you).
Record.findOne({ 'owner': owner}, {}, {sort: { date: -1 }}, function(err, record){
if (err) {
//don't just ignore this, log or bubble forward via callbacks
return;
}
if (!record) {
//Record not found, log or send 404 or whatever
return;
}
record.array.forEach(function (item) {
item.score = 0;
item.changed = true;
});
//Now, mongoose can't automatically detect that you've changed the contents of
//record.array, so tell it
//see http://mongoosejs.com/docs/api.html#document_Document-markModified
record.markModified('array');
record.save();
});
If you have a mongoose object of a document, you can of course update the array as in the question, with the following Caveat.
This is in fact a mongoose gotcha. Mongoose cannot track changes in the array of mixed, one has to use markModified:
doc.mixed.type = 'changed';
doc.markModified('mixed.type');
doc.save() // changes to mixed.type are now persisted

Node.js MongoDB Upsert update

I'm writing a little application which scores keywords. So if "beirut" and "education" get entered in, if they haven't been seen before, I want to create a mongo entry, and give them a score of 1. If they have, I want to increment their score by one. I'm trying to do this with one update command, but I think I might be doing it wrong.
Ranking is the object representing the database
"key" is the keyword
rankingdb.update(
{keyword:key},
{keyword:key, {$inc:{score:1}}},
{upsert:true, safe:false},
function(err, data) {
if (err) {
console.log(err);
}
else {
console.log("score succeeded");
}
}
);
SyntaxError: Unexpected token {
Can you not create a brand new document with an increment?
Your general approach is right, but as the error message suggests, you've got a syntax problem in your code.
Try this instead:
rankingdb.update(
{keyword: key},
{$inc: {score: 1}},
{upsert: true, safe: false},
function(err,data){
if (err){
console.log(err);
}else{
console.log("score succeded");
}
}
);
When an upsert needs to create a new object it combines the fields from the selector (first parameter) and the update object (second parameter) when creating the object so you don't need to include the keyword field in both.
Note that update() is deprecated in the 2.0 driver, so you should now use either updateOne() or updateMany().

Resources