Retrieve data from mongodb and display to terminal - javascript

Background
I just started learning how to use node.js and mongodb.
iv been able to create a db and connect to it / write a collection using the code below
var url = "localhost:27017/TheDatabase";
var collections = ["Location"];
var mongojs = require("mongojs")
var db = mongojs(url, collections);
var object = {
"place" : {
"address" : "123 road",
"code" : "ABC CDE",
"letters" : "AA",
"coord" : [ 99.55, -20.5 ]
},
"keyword1" : "World",
"keyword2" : "Biomech",
"keyword3" : "Spotify",
"_id" : "1"
}
db.Location.save(object);
The Problem
I was unable to successfully retrieve the data from this database/collection.
What i want to do is just retrieve "object" from db and display it to terminal to see i accomplished the store/retrieve correctly.
What i'v tried
I'v opened mongo.exe and tried running
use TheDatabase
show collections
db.Location.find()
and was able to see the data. I'm not sure how i implement this in my node.js application.
Edit
db.Location.find(function (err, docs) {
console.log(docs);// docs is an array of all the documents in mycollection
})

Related

Query orderByChild in Firebase Realtime Database not working?

I've seen many posts and solutions that are precisely what I need but when I implement it it doesn't work. I'm using the Firebase Realtime Database and I'm trying to search all "Name" children for a specific name. In this example I added the strings directly, but I'll be using a variable based on user input in the future. Here is my database structure as I see it in firebase:
{
"kjienk24dfwefn" : {
"FriendID" : "fr1959l9591i4925a",
"Name" : "Test Dummy2",
"email": "something#gmail.com",
"Status" : "InGame"
},
"kjienk24kdfiwne" : {
"FriendID" : "fr2812p8092m3604l",
"Name" : "Test Dummy",
"email":"some#something.com"
"Status" : "Online"
},
"kjienk24udfjjo" : {
"FriendID" : "fr7605h9204f8099g",
"Name" : "Test Dummy3",
"email": "fake#fakeemail.com"
"Status" : "Offline"
}
}
And here is the code I'm using to query the "Name" (usersRef points to "firebase.database().ref()"). I've seen lots of examples of this online and I'm not sure what I'm doing incorrectly.
usersRef.orderByChild("Name").equalTo("Test Dummy").on("value", function(snapshot) {
//This is where I expect to see Test Dummy on the console.
console.log(snapshot.val())
});
EDIT: Here is the initialization of usersRef. Haven't had any problems reading and writing to the database. Standard firebaseConfig.:
const fbApp = firebase.initializeApp(firebaseConfig);
const db2 = fbApp.database("https://firebasedatabaseurl.com/")
const usersRef = db2.ref();
Test with parent node:
Thanks all in advance!
You want to load data from the users node, but that is currently not mentioned anywhere in your code. So Firebase is querying the root of your database, and the child nodes under there (like users) don't have a Name property, so you get no results.
const usersRef = db2.ref().child("users");
Or:
const usersRef = db2.ref("users");

Dialogflow and Firebase - Iterate list of data

Making a chatbot that recommends a movie based on genre and other factors. Trying to iterate through an object retrieved from a firebase realtime database in DialogFlow. I'm using forEach but when triggered it displays "Not Available".
Preferably, the function would display a random item from the list but I have not reached that part yet - any advice on this too would be appreciated.
Below is my code.
function displayData(agent) {
return ref.orderByChild("genre1").equalTo("Comedy").on("child_added", function(snapshot) {
let obj = {};
obj = snapshot.val();
obj.forEach(function(childSnapshot) {
var childData = childSnapshot.val();
agent.add(childData.name);
});
});
}
Below is a sample database
{
"movies" : {
"movie1" : {
"genre1" : "Sci-Fi",
"genre2" : "Horror",
"name" : "Alien",
"rating" : 84,
"year" : 1979
},
"movie2" : {
"genre1" : "Comedy",
"genre2" : "Parody",
"name" : "Airplane",
"rating" : 97,
"year" : 1980
},
"movie3" : {
"genre1" : "Comedy",
"genre2" : "Teen",
"name" : "Superbad",
"rating" : 88,
"year" : 2007
}
}
}
The base problem is that the Dialogflow library requires you to return a Promise, however you're using the callback version of the call instead of the Promise version of the call. You need to change this to something more like
function displayData(agent) {
return ref.orderByChild("genre1").equalTo("Comedy").on("child_added")
.then( snapshot => {
// Do something with the snapshot
});
}
(You probably also want to use once("value") instead of on("child_added"), since you don't need updates to be sent in realtime.)
While the forEach() is probably working correctly, there is a minor problem that not all agents will return all the text that has been .add()ed. So you probably only want to call .add() once.
Since you really only want once of these children, picked randomly, you can just treat this as a JavaScript object if you have enough memory. So you could just get the keys with Object.keys(obj), pick one of the keys by random, and then get the full value of the result.

Meteor: Return only single object in nested array within collection

I'm attempting to filter returned data sets with Meteor's find().fetch() to contain just a single object, it doesn't appear very useful if I query for a single subdocument but instead I receive several, some not even containing any of the matched terms.
I have a simple mixed data collection that looks like this:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"items" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06"),
"slug" : "this-is-a-long-slug",
"title" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6"),
"slug" : "mc",
"title" : "Technology"
}
]
}
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e8"),
"name" : "Sitewide",
"items" : [
{
"_id" : ObjectId("57a38bc75ac9e2efc0fa09c9"),
"slug" : "example",
"name" : "Single Example"
}
]
}
I can easily query for a specific object in the nested items array with the MongoDB shell as this:
db.categories.find( { "items.slug": "mc" }, { "items.$": 1 } );
This returns good data, it contains just the single object I want to work with:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"items" : [
{
"_id" : ObjectId("57a38b985ac9e2efc0fa09c8")
"slug" : "mc",
"name" : "Single Example"
}
]
}
However, if a similar query within Meteor is directly attempted:
/* server/publications.js */
Meteor.publish('categories.all', function () {
return Categories.find({}, { sort: { position: 1 } });
});
/* imports/ui/page.js */
Template.page.onCreated(function () {
this.subscribe('categories.all');
});
Template.page.helpers({
items: function () {
var item = Categories.find(
{ "items.slug": "mc" },
{ "items.$": 1 } )
.fetch();
console.log('item: %o', item);
}
});
The outcome isn't ideal as it returns the entire matched block, as well as every object in the nested items array:
{
"_id" : ObjectId("570d20de3ae6b49a54ee01e7"),
"name" : "Entertainment",
"boards" : [
{
"_id" : ObjectId("57a38b5f2bd9ac8225caff06")
"slug" : "this-is-a-long-slug",
"name" : "This is a title"
},
{
"_id" : ObjectId("57a38b835ac9e2efc0fa09c6")
"slug" : "mc",
"name" : "Technology"
}
]
}
I can then of course filter the returned cursor even further with a for loop to get just the needed object, but this seems unscalable and terribly inefficient while dealing with larger data sets.
I can't grasp why Meteor's find returns a completely different set of data than MongoDB's shell find, the only reasonable explanation is both function signatures are different.
Should I break up my nested collections into smaller collections and take a more relational database approach (i.e. store references to ObjectIDs) and query data from collection-to-collection, or is there a more powerful means available to efficiently filter large data sets into single objects that contain just the matched objects as demonstrated above?
The client side implementation of Mongo used by Meteor is called minimongo. It currently only implements a subset of available Mongo functionality. Minimongo does not currently support $ based projections. From the Field Specifiers section of the Meteor API:
Field operators such as $ and $elemMatch are not available on the client side yet.
This is one of the reasons why you're getting different results between the client and the Mongo shell. The closest you can get with your original query is the result you'll get by changing "items.$" to "items":
Categories.find(
{ "items.slug": "mc" },
{ "items": 1 }
).fetch();
This query still isn't quite right though. Minimongo expects your second find parameter to be one of the allowed option parameters outlined in the docs. To filter fields for example, you have to do something like:
Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items": 1
}
}
).fetch();
On the client side (with Minimongo) you'll then need to filter the result further yourself.
There is another way of doing this though. If you run your Mongo query on the server, you won't be using Minimongo, which means projections are supported. As a quick example, try the following:
/server/main.js
const filteredCategories = Categories.find(
{ "items.slug": "mc" },
{
fields: {
"items.$": 1
}
}
).fetch();
console.log(filteredCategories);
The projection will work, and the logged results will match the results you see when using the Mongo console directly. Instead of running your Categories.find on the client side, you could instead create a Meteor Method that calls your Categories.find on the server, and returns the results back to the client.

Meteor Mongo not working but standalone MongoDB is

I have the following document
{
"_id" : ObjectId("5464e68481f8252e74f6e0ef"),
"message" : "Hello World!",
"timestamp" : ISODate("2014-11-13T17:12:36.547Z"),
"sender" : "D3EkLv8vatX3xfCGE",
"receiver" : [
{
"id" : "YzhZchz4AwCAd3q2R",
"seen" : false
},
{
"id" : "sm2W28EKYmHz29Aoj",
"seen" : false
}
],
"saved" : false
}
That's the basic structure. Now I want to get all the documents that have the current user's ID. The id can be in the sender field or one of the object in the receiver array. This works fine:
db.messages.find({ sender: "D3EkLv8vatX3xfCGE" })
But the following query doesn't work on the Meteor Mongo instance but does so in Mongo 2.6:
db.messages.find({ receiver: {id: "YzhZchz4AwCAd3q2R"} })
Is there any way I can get this to work. Also, the above query works on Minimongo but doesn't work on Meteor's bundled mongo(meteor mongo) which is currently at v2.4.9.
On mongo shell this query seems to work:
db.messages.find({ "receiver.id": "YzhZchz4AwCAd3q2R"} )
You can find all of the documents were a particular user is a receiver using receiver.id in your selector like so:
Messages.find({'receiver.id': 'YzhZchz4AwCAd3q2R'})
If you wanted to find all documents where a particular user was either a receiver or a sender you could do this:
var id = 'YzhZchz4AwCAd3q2R';
Messages.find({$or: [{'receiver.id': id}, {sender: id}]});

MongoDB aggregation: How to extract the field in the results

all!
I'm new to MongoDB aggregation, after aggregating, I finally get the result:
"result" : [
{
"_id" : "531d84734031c76f06b853f0"
},
{
"_id" : "5316739f4031c76f06b85399"
},
{
"_id" : "53171a7f4031c76f06b853e5"
},
{
"_id" : "531687024031c76f06b853db"
},
{
"_id" : "5321135cf5fcb31a051e911a"
},
{
"_id" : "5315b2564031c76f06b8538f"
}
],
"ok" : 1
The data is just what I'm looking for, but I just want to make it one step further, I hope my data will be displayed like this:
"result" : [
"531d84734031c76f06b853f0",
"5316739f4031c76f06b85399",
"53171a7f4031c76f06b853e5",
"531687024031c76f06b853db",
"5321135cf5fcb31a051e911a",
"5315b2564031c76f06b8538f"
],
"ok" : 1
Yes, I just want to get all the unique id in a plain string array, is there anything I could do? Any help would be appreciated!
All MongoDB queries produce "key/value" pairs in the result document. All MongoDB content is basically a BSON document in this form, which is just "translated" back to native code form by the driver to the language it is implemented in.
So the aggregation framework alone is never going to produce a bare array of just the values as you want. But you can always just transform the array of results, as after all it is only an array
var result = db.collection.aggregate(pipeline);
var response = result.result.map(function(x) { return x._id } );
Also note that the default behavior in the shell and a preferred option is that the aggregation result is actually returned as a cursor from MongoDB 2.6 and onwards. Since this is in list form rather than as a distinct document you would process differently:
var response = db.collection.aggregate(pipeline).map(function(x) {
return x._id;
})

Categories