Check if mongo document field exists - mongodb

I want to check if the field "imageUrl" are inserted from a form into a MongoDb collection.
If it has a value, I want to return the URL, else return false. I'm not used to Mongo, and wonder how I can achieve this. Not every entry have a imageUrl field, but some do. So I need to check if it even exists for every document.
Here's my helper, where I want to have the logic:
Template.CatchesList.helpers({
catches: function () {
return Catches.find({}, {sort: {date: -1}});
},
image: function() {
if (this.imageURL) // Need proper logic here
return true;
else
return false;
}
});
And in my template:
{{#if image}}
<td><img width="100" src="{{imageUrl}}"></td>
{{/if}}

MongoDB has the $exists operator to filter results where the property does not exist in the document. So you can change your query to:
return Catches.find({ "imageUrl": { "$exists": true }}, { "sort": { "date": -1 }});
And then only items that have the property will be returned.
If you are only talking about templates, then a simple conditional test on the field returns logically where it is present or not present:
{{#each catches}}
{{> catch }}
{{/each}}
Then:
<template name="catch">
<tr>
<!-- other fields -->
<td>{{#if imageUrl}}<img width="100" src="{{imageUrl}}">{{/if}}</td>
</tr>
</template>
Where only the logic contained within {{#if}}{{/if}} will actually render.

I did this in an app and it worked for me:
Courses.find({owned_by_contract:user_contract._id}).forEach(function(doc){
var foo = ("your_field_name" in doc) ? doc.course_objective_english.value:"N/A";
}):

Related

update specific field in meteor

I want to update only the name field, the problem with the code I have is that if I update a document, all the mongo documents are updated.
As I update a document in specific, I must admit that I am new to this mongo so any help I thank you.
Client
updatename.html
<template name="updatename">
<form class="editor-container">
<input class=“save” type="text" id="card" value=“{{name}}”>
<button type="button" class=“save” id="save">save</button>
</form>
</template>
updatename.js
Template.updatename.events({
'click .save’: function (e, t) {
e.preventDefault();
FlowRouter.watchPathChange();
var name = FlowRouter.current().params._id;
var name = $('#card').val();
Meteor.call('name.update',name);
FlowRouter.go('/');
}
});
Server
name.js
Meteor.methods({
'name.update'( name) {
Name.update({
Name.update({},{ $set: { nam: name }},{multi:true})
});
}
});
I recommend few improvisations over your Meteor code.
Atleast use Title Case/ CamelCase for better readability of the template name and Meteor Methods for other developer.
use submit .formClassName instead of using click .save, also specifiy parameter name with sincerity like function (event, template)
When you updating document for logged user and not other user, as dmayo mentioned in the code use Name.update({_id: Meteor.userId()},{ $set: {nam: name}}), but there is no sense of specifying { multi: true } when you know that there is going to be only 1 record when you are updating. You can use { multi: true } when you desire to impact many records based on criteria that are definitely going to return more than 1 record.
use check(name, String) in Meteor.method call to ensure what you are sending to the server is eligible for further operations.
Use aldeed autoforms when you know there is no out of the box implementation and is going to be simple.
Below is the improvised code for better readability and up to standards
Client
update-name.html
<template name="UpdateName">
<form class="editorContainerForm">
<input type="text" id="card" value=“{{name}}”>
<button type="submit">Save</button>
</form>
</template>
update-name.js
Template.UpdateName.events({
'submit .editorContainerForm’: function (event, template) {
event.preventDefault();
FlowRouter.watchPathChange();
var name = FlowRouter.current().params._id;
var name = $('#card').val();
Meteor.call('updateName',name, function(error, response){
if(error){
// Show some BERT ERROR message for better user experience
// use "meteor add themeteorchef:bert" to add package
} else {
// Show some BERT SUCCESS message for better user experience
});
FlowRouter.go('/');
}
});
Server
name.js
Meteor.methods({
updateName( name ) {
check(name, String);
Name.update({ _id: Meteor.userId },{ $set: { name: name }});
// Use below code only if you know there can be multiple records for same ID
// Name.update({ _id: Meteor.userId },{ $set: { name: name }}, { multi: true });
}
});
In your name.js file (on the server) your mongo query is empty, so when mongo queries your database, it matches all of the documents/records.
Name.update(query, changes, options)
That is the format per the mongo docs. You need to have a unique identifier. Your form is saving a "name", and that's what you are passing to the Meteor.method, but you're not telling the method who's changing their name. If the user is logged in, then you can just use the meteor unique id Meteor.userId()
Name.update({_id: Meteor.userId()},{ $set: {nam: name}},{multi:true})
Also, your option multi:true says to update any and all documents that match the query. If in your original method as written, you had multi:false (the default) then only one document would have been updated (but probably not the one you wanted as the first match would have been updated because of your empty query field.
Mongo docs: https://docs.mongodb.com/manual/reference/method/db.collection.update/
Metor docs: https://docs.meteor.com/api/collections.html#Mongo-Collection-update

Cannot access or use documents showing in mongo db terminal

I created a collection called Stampest that stores a reference of an uploaded image and a title string, created by a user. Using the ostrio:autoform package.This package creates a collection called Images where all the user uploaded images are stored and hense referenced to/from.
When I query mongo in my terminal using
db.stampest.find({})
I get the entries
Which shows that there are documents in the database, in the Stampest Collection. But the PROBLEM is that when I look at the collection in Meteor Toys debug, it says its empty, and when I insert a document, in this case, the image and the title, the collection changes to 1 for a split second and geos back to 0. There are no error from the terminal or console
As a consequence, I cannot access these documents, what can I do?
This is the schema.js
Schemas = {};
Stampest = new Meteor.Collection('stampest');
Stampest.allow({
insert: function (userId, doc) {
return userId;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return doc.userId === userId;
},
remove: function (userId, doc) {
// can only remove your own documents
return doc.userId === userId;
}
});
Schemas.Stampest = new SimpleSchema({
title: {
type: String,
max: 60
},
picture: {
type: String,
autoform: {
afFieldInput: {
type: 'fileUpload',
collection: 'Images',
// uploadTemplate: 'uploadField' // <- Optional
// previewTemplate: 'uploadPreview' // <- Optional
}
}
}
});
Stampest.attachSchema(Schemas.Stampest);
The publish is like this:
Meteor.publish('stampest', function () {
return Stampest.find({author: this.userId}).fetch();
console.log(Stampest.find());
});
The user inserts the image and the title like this:
<template name="createStamp">
<div class="grid-block">
<div class="grid-container">
<div class="upload-img">
{{file.original.name}}
</div>
<div class="new-stamp-container">
{{> quickForm collection="Stampest" type="insert" id="insertStampForm" class="new-stamp-form"}}
</div>
</div>
</div>
</template>
From what I see in your code, you are returning an Array of db items and not a Cursor in your code.
If you take a look at https://docs.meteor.com/api/pubsub.html, you'll notice that regular publications return simple cursors or array of cursors but never your fetched data.
edit: also, the console.log in your publication will never be interpreted as it returns on the previous line.

Sorting users using date from separate collection

I'm trying to get return a list of users based on their accountActiveDate which is stored in a separate collection. If I console.log candidateUserIDByDate it returns the users in the correct order however when I return Meteor.users.find using the var candidateUserIDByDate its not sorted.
Path: sort.js
let sortCandidatesByDate = CandidateAccountStatus.find({}, {sort: {accountActiveDate: 1}}).fetch();
let candidateUserIDByDate = _.map(sortCandidatesByDate, function(obj) {
return obj.candidateUserId;
});
return Meteor.users.find({$and: [{_id: { $ne: Meteor.userId() }}, {_id: { $in: candidateUserIDByDate }}]});
I think a (probably hackish) solution would be, returning the CandidateAccountStatus and inside the loop, using another helper to return the correct user like this:
Template helpers:
status: function(){
//you might want to do {$ne: {Meteor.userId()}} for the correct field
//in your selector if you don't want currentUser status
return CandidateAccountStatus.find({}, {sort: {accountActiveDate: 1}})
},
statusUser: function(){
//change correctField to how you save the userId to
//your CandidateAccountStatus schema
return Meteor.users.findOne({_id: this.correctField})
}
HTML
{{#each status}}
{{#with statusUser}}
<!-- You have the user object here -->
{{_id}} <!-- gives the userId -->
{{/with}}
{{/each}}

Iterating unknown object in Meteor

I am having trouble displaying data much like what is described here, but my object is not conveniently labelled in numbers: How do I iterate over an unknown object in a Meteor Spacebars template?
Data maybe be nested more than once, and might differ but always end in an array.
I am open to new data structures too.
Sample Data:
{
"Category A":
{
"Sub-Category1":
{
"Sub-Sub-Category1": ['Value1', 'Value2']
},
"Sub-Category2":
{
"Sub-Sub-Category2": ['Value3'],
"Sub-Sub-Category3": ['Value4']
}
},
"Category B":
{
"Sub-Category1": ['Value5']
}
}
You're going to need a recursive template to handle arbitrary nesting, a helper that enumerates the keys of an object, and a helper that gets the value of the parent object corresponding to a key.
html:
<template name="nest">
{{#if isArray}}
{{#each this}}
{{this}} <!-- we're assuming that array elements aren't themselves objects -->
{{/each}}
{{#elseif isObject}}
{{#each keys}}
{{#with value}}
{{> nest }}
{{/with}}
{{/each}}
{{else}} <!-- catch the case of a scalar key value (no array) -->
{{this}}
{{/if}}
</template>
js:
Template.nest.helpers({
isArray(){
return typeof(this) === "object" && this.length && this.length > 0;
},
isObject(){
return typeOf(this) === "object" && !this.length;
},
keys(){
return Object.keys(this); // returns an array of strings
},
value(){
return Template.parentData()[this]; // look up the hierarchy to get the parent object then select the data for the current key
}
});

Repeating Meteor template with a specific item in mongodb collection

I have a collection with this item:
{
"item1": ["foo", "bar", "baz"],
"item2": ...
}
I made a helper function to repeat a template for each item in item1
Template.temp.helpers({
items: function() {
return Col.find({},{item1:1});
}
});
and this is the template
<template name="temp">
{{#each items}}
{{> anotherTemplate}}
{{/each}}
</template>
But I get back an empty array. Why doesn't it work?
Try with {{#each items.item1}}
Because, Col.find({},{item1:1}) just remove all other field from result.
Limit Fields to Return from a Query
It's like SELECT item1 FROM table in SQL
If you need repeat your template for each item in item1, you need to precise which array should be use.
<template name="temp">
{{#each items.item1}}
{{> anotherTemplate}}
{{/each}}
</template>
Meteor mongo methods are a little different you cannot use.
return Col.find({},{item1:1});
you can use it this way:
return Col.find({},{fields:{'item1':1}});
Maybe you want:
{{#each items}}
{{#each item1}}
{{> anotherTemplate}}
{{/each}}
{{/each}}
Or this:
Template.temp.helpers({
items: function() {
return Col.find({},{item1:1}).map(function(item){
return item.item1
})
}
});
That way items will return the item1 array. Originally it was returning an array of objects with just one element, the item1 arrays of each object:
[{
item1: ["foo","bar","baz"]
},
{
item1: ["lah","nah","jah"]
},
{
item1: ["see","gee","bee"]
}]
this way you'll get an array of arrays: [["foo","bar","baz"], ["lah","nah","jah"], ["see","gee","bee"]]
I think you need to do return something like this from helper
return Col.findOne({}).item1
It should work now
Thanks