I use Meteor to query a mongo collection. It has for example the following entry:
{
"_id": "uCfwxKXyZygcWQeiS",
"gameType": "foobar",
"state": "starting",
"hidden": {
"correctAnswer": "secret",
"someOtherStuff": "foobar"
},
"personal": {
"Y73uBhuDq2Bhk4d8W": {
"givenAnswer": "another secret",
},
"hQphob8s92gbEMXbY": {
"givenAnswer": "i have no clue"
}
}
}
What I am trying to do now is:
don't return the values behind "hidden"
from the "personal" embedded document only return the values for the asking user
In code it would look something like this:
Meteor.publish('game', function() {
this.related(function(user) {
var fields = {};
fields.hidden = 0;
fields.personal = 0;
fields['personal.' + this.userId] = 1;
return Games.find({}, {fields: fields});
}, Meteor.users.find(this.userId, {fields: {'profile.gameId': 1}}));
}
Obviously this won't work, because MongoDB won't allow mixed includes and excludes. On the other hand, I cannot switch to "specify only the included fields", because they can vary from gameType to gameType and it would become a large list.
I really hope that you can help me out of this. What can I do to solve the problem?
Typical example of where to use the directly controlled publication features (the this.added/removed/changed methods).
See the second example block a bit down the page at http://docs.meteor.com/api/pubsub.html#Meteor-publish.
With this pattern you get complete control of when and what to publish.
Related
I'm using Dynamoose to simplify my interactions with DynamoDB in a node.js application. I'm trying to write a query using Dynamoose's Model.query function that will search a table using an index, but it seems like Dynamoose is not including all of the info required to process the query and I'm not sure what I'm doing wrong.
Here's what the schema looks like:
const UserSchema = new dynamoose.Schema({
"user_id": {
"hashKey": true,
"type": String
},
"email": {
"type": String,
"index": {
"global": true,
"name": "email-index"
}
},
"first_name": {
"type": String,
"index": {
"global": true,
"name": "first_name-index"
}
},
"last_name": {
"type": String,
"index": {
"global": true,
"name": "last_name-index"
}
}
)
module.exports = dynamoose.model(config.usersTable, UserSchema)
I'd like to be able to search for users by their email address, so I'm writing a query that looks like this:
Users.query("email").contains(query.email)
.using("email-index")
.all()
.exec()
.then( results => {
res.status(200).json(results)
}).catch( err => {
res.status(500).send("Error searching for users: " + err)
})
I have a global secondary index defined for the email field:
When I try to execute this query, I'm getting the following error:
Error searching for users: ValidationException: Either the KeyConditions or KeyConditionExpression parameter must be specified in the request.
Using the Dynamoose debugging output, I can see that the query winds up looking like this:
aws:dynamodb:query:request - {
"FilterExpression": "contains (#a0, :v0)",
"ExpressionAttributeNames": {
"#a0": "email"
},
"ExpressionAttributeValues": {
":v0": {
"S": "mel"
}
},
"TableName": "user_qa",
"IndexName": "email-index"
}
I note that the actual query sent to DynamoDB does not contain KeyConditions or KeyConditionExpression, as the error message indicates. What am I doing wrong that prevents this query from being written correctly such that it executes the query against the global secondary index I've added for this table?
As it turns out, calls like .contains(text) are used as filters, not query parameters. DynamoDB can't figure out if the text in the index contains the text I'm searching for without looking at every single record, which is a scan, not a query. So it doesn't make sense to try to use .contains(text) in this context, even though it's possible to call it in a chain like the one I constructed. What I ultimately needed to do to make this work is turn my call into a table scan with the .contains(text) filter:
Users.scan({ email: { contains: query.email }}).all().exec().then( ... )
I am not familiar with Dynamoose too much but the following code below will do an update on a record using node.JS and DynamoDB. See the key parameter I have below; by the error message you got it seems you are missing this.
To my knowledge, you must specify a key for an UPDATE request. You can checks the AWS DynamoDB docs to confirm.
var params = {
TableName: table,
Key: {
"id": customerID,
},
UpdateExpression: "set customer_name= :s, customer_address= :p, customer_phone= :u, end_date = :u",
ExpressionAttributeValues: {
":s": customer_name,
":p": customer_address,
":u": customer_phone
},
ReturnValues: "UPDATED_NEW"
};
await docClient.update(params).promise();
I'm building a little web-app to practice and learn Vue.js and working with APIs.
For a particular problem I want to solve, I would like to return the object that has the matching uuid that I request.
With my current knowledge, I understand I can do this by implementing some sorts and loops logic.
However I'm still new with JS, Vue.js, so I'm not sure if there is a better way to approach this.
Is there a built in function, or some form of "best practice" to approach this?
methods: {
fetchItem(row) {
// row.target_uuid -- this is the UUID I want
// this.$props.todoItems; -- this contains the json objects
// return this.$props.todoItems[i] where this.$props.todoItems[i]['uuid'] == row.target_uuid
},
This is a snippet of my $props.todoItems for context
[
{
"title": "Install Maris",
"uuid": "9ec9ea6b-0efc-4f6a-be2e-143be5748d3a",
"field_completed": "False"
},
{
"title": "Figure out why VS Code sucks",
"uuid": "85120da5-ee59-4947-a40f-648699365c73",
"field_completed": "False"
},
{
"title": "Start designing portfolio",
"uuid": "243c1960-7ade-4a68-9a74-0ccc4afa3e36",
"field_completed": "False"
},
{
"title": "Meal Prep",
"uuid": "85b64b18-9110-44d8-bd2d-8f818b0a810f",
"field_completed": "False"
},
{
"title": "Sharpen knives",
"uuid": "8a7ac5f6-8180-4f20-b886-628fd3bcfc85",
"field_completed": "False"
},
{
"title": "Set up SSH keys",
"uuid": "f879c441-8c05-4f24-9226-125c62576297",
"field_completed": "False"
}
]
If you know you're looking for exactly one item (or the first item that matches) you should take a closer look at the Array.find() method provided by JS. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
Also take a look at all the other methods the Array prototype provides, most of them are fairly descriptive and solve most of the basic problems you'll encounter.
To use this in your Vue app you can either have a method that returns your todo based on a provided uid like this
todoByUid(uidToFind) {
return this.todos.find(todo => todo.uid == uidToFind)
}
If you only care about a currently selected item a computed value as Jacob mentioned is the way to go:
computed() {
selectedTodo() {
return this.todos.find(todo => todo.uid == this.selectedUid)
}
}
Here's my situation, I have a JSON that looks somewhat like this:
{
"items": [{
"type": "condition",
"data": {
"type": "comparison",
"value1": {
"source": "MyType1",
"component": "Attribute1"
},
"value2": {
"source": "MyType2",
"component": "Attribute2"
},
"operator": "gt"
}
},
{
"type": "then",
"data": {
"result": "failed",
"message": "value1 is too high"
}
}
]
}
and would want it to translate to:
if (MyType1.Attribute1 > MyType2.Attribute2) {
result = "failed";
console.log("value1 is too high");
}
Now my problem is, I don't know how I would translate the entries of value1 and value2 to actual code, or rather, how I could access the Object MyType1(maybe through something like getAttribute("MyType1")).
Since I am going to have a whole bunch of sources which each have different components, I cant really write a huge dictionary. Or I would like to avoid it.
The goal is to allow creating if - then - statements via some interactive UI, and I figured it'd be best to save that code as .json files. (Think rule management system).
So, TL,DR, How would I access a Class Attribute this.MyType, if I only have a String MyType to go from? And how would I access the value this.MyType.MyValue, if I get another String MyValue?
Thanks in advance.
Edit:
I'd really like to avoid using eval, for obvious reasons. And if I have to - I guess I would need to create Dictionaries for possible JSON Values, to validate the input?
You need some kind of parser. At first we need some way to store variables and maybe flags:
const variables = {};
var in = false;
Then we go through the code and execute it:
for(const command of items){
switch( command.type ){
case "condition":
//...
case "then":
//...
}
}
To access a variable we can simply do
var current = variables[ identifier ];
To store its the other way round:
variables[ identifier ] = current;
i'm not sure if the title of the questions fits, if you know a better one, let me know ;)
I just named it like this, because i'm thinking if i could solve my problem with a custom reduce function.
I have two types of objects:
Vehicles:
{
"id": "1G1JC5444R7252367",
"type": "Vehicle"
}
Users:
{
"company": "companyname",
"type": "User",
"parts": [
{
"company": "companyname",
"id": "1G1JC5444R7252367",
"active": true
},
{
"company": "companyname",
"id": "1G1135644R7252367",
"active": false
}
]
}
What i want is a View which returns me all vehicles of a certain company. But the company is only stored in the User object.
This is how far I got in the mapfunction:
function (doc, meta) {
if(doc.type == 'User'){
if(doc.parts){
Array.prototype.contains = function ( needle ) {
for (var i in this) {
if (this[i] == needle) return true;
}
return false;
};
var ids = new Array(doc.parts.length);
for(var k in doc.parts){
if(doc.parts[k].active) {
if(!vins.contains(doc.parts[k].id)) {
if (doc.parts[k].company && doc.parts[k].id ) {
ids.push(doc.parts[k].id);
emit(doc.parts[k].company, doc.parts[k].id);
}
}
}
}
}
}
}
But this only returns me the company as key and the id of the vehicle as value. So i get a User document. Can I somehow loop through the documents again in the map function and get all vehicles according to the ids in my ids array?
Saving the company in the vehicle itself also is not desired, because the company is not the vehicles company itself but the company of the parts.
Thanks for any help in forward.
A Couchbase view can only operate on the document presented to it. As you discovered, it can only partially do what you want.
The real problem isn't the view though but is your data model. You appear to have designed your data model as if you were using a relational database. The calculation you are attempting is a kind of join.
A fundamental concept with document databases is that a document should represent all of the information pertinent to some kind of event. This concept is what allows document databases to horizontally scale. You should not worry about data duplication. Locality of access is the key to an appropriate map-reduce data model.
I would redesign your data model.
I have a network array like the following way
"network_contents": [
{
"facebook":"contents to all pages",
},
{
"twitter":"twiter contents",
},
{
"linkedin":"linked in contents",
}
]
I would like to add some keys to that array bases on its content. If it is facebook the key should be facebook, if it is twitter key should be twitter. But not sure how to do it.
My requirement is to access network array contents, but it may or may not content these facebook, twitter, linked in values. I need to access its values. When i assign a key value will be easy to fetch its contents. So i tried this way to loop through the array
message.network_contents.forEach( function (nwContent) {
if(nwContent.twitter) {
console.log('nw content', nwContent.twitter);
}
})
can i create an array in this foreach loop like the following way.
{
"data": [
{
"facebook": {
"facebook": "facebook content"
},
"twitter": {
"twitter": "twitter content"
}
}
]
}
Your help is much appreciated thanks
Implementation of what I said in the comment:
var oldsies = stuff.network_contents;
var newsies = stuff.network_contents = {};
oldsies.forEach(function(network) {
var name = Object.keys(network)[0];
newsies[name] = network;
});
You gave an example of a JS object and not a dictionary and therefore cant add key-values.
You need something like this:
var network_contents = [];
network_contents["facebook"] = {config1: {name:"config1", value:"value1"}};
network_contents["twitter"] = {config2: {name:"config2", value:"value2"}};
example:
network_contents["facebook"].config1.value; // will return "value1"
You can covert your object to a dictionary easily.