模拟到SQL' JOIN'对于Javascript对象?

时间:2014-03-23 16:20:15

标签: javascript arrays join

对于表示为Javascript对象数组的表,SQL'JOIN'的实用模拟是什么? Javascript Array.join和D3.js'd3.merge`的概念不同。

E.g。 SELECT * FROM authors LEFT JOIN books ON authors.id = books.author_id

第一张表:

var authors = 
[  { id: 1, name: 'adam'},
   { id: 2, name: 'bob'},
   { id: 3, name: 'charlie'}, ...
]

第二张表:

var books = 
[  { author_id: 1, title: 'Coloring for beginners'}, 
   { author_id: 1, title: 'Advanced coloring'}, 
   { author_id: 2, title: '50 Hikes in New England'},
   { author_id: 2, title: '50 Hikes in Illinois'},
   { author_id: 3, title: 'String Theory for Dummies'}, ...
]

这些表是使用D3.js d3.csv()从CSV加载的,所以D3.js已经开放给其他库,但通常更喜欢直接编码,如果不是太远的话。

我看到使用RethinkDB的Native way to merge objects in Javascript,这似乎超过了顶部,但这就是主意。

6 个答案:

答案 0 :(得分:11)

基本上,像这样:

// first, build an easier lookup of author data:
var authormap = {};
authors.forEach(function(author) {authormap[author.id] = author;});

// now do the "join":
books.forEach(function(book) {
    book.author = authormap[book.author_id];
});

// now you can access:
alert(books[0].author.name);

答案 1 :(得分:2)

您可以使用Alasql JavaScript SQL库执行此操作:

var res = alasql('SELECT * FROM ? authors \
       LEFT JOIN ? books ON authors.id = books.author_id',[authors, books]);

使用jsFiddle中的数据尝试this example

您也可以将CSV数据直接加载到SQL表达式中:

alasql('SELECT * FROM CSV("authors.csv", {headers:true}) authors \
            LEFT JOIN CSV("books.csv", {headers:true}) books \
            ON authors.id = books.author_id',[], function(res) {
      console.log(res);
 });

答案 2 :(得分:1)

这是受@ Niet的回答启发的。

我遇到了重复数据的问题,所以我添加了在加入之前在查找表中克隆记录的步骤。

var authors = [{
    id: 1,
    name: 'adam'
}, {
    id: 2,
    name: 'bob'
}, {
    id: 3,
    name: 'charlie'
}];

var books = [{
    author_id: 1,
    title: 'Coloring for beginners'
}, {
    author_id: 1,
    title: 'Advanced coloring'
}, {
    author_id: 2,
    title: '50 Hikes in New England'
}, {
    author_id: 2,
    title: '50 Hikes in Illinois'
}, {
    author_id: 3,
    title: 'String Theory for Dummies'
}];

function joinTables(left, right, leftKey, rightKey) {

    rightKey = rightKey || leftKey;

    var lookupTable = {};
    var resultTable = [];
    var forEachLeftRecord = function (currentRecord) {
        lookupTable[currentRecord[leftKey]] = currentRecord;
    };

    var forEachRightRecord = function (currentRecord) {
        var joinedRecord = _.clone(lookupTable[currentRecord[rightKey]]); // using lodash clone
        _.extend(joinedRecord, currentRecord); // using lodash extend
        resultTable.push(joinedRecord);
    };

    left.forEach(forEachLeftRecord);
    right.forEach(forEachRightRecord);

    return resultTable;
}
var joinResult = joinTables(authors, books, 'id', 'author_id');
console.log(joinResult);

结果是

[
    {
        "id": 1,
        "name": "adam",
        "author_id": 1,
        "title": "Coloring for beginners"
    },
    {
        "id": 1,
        "name": "adam",
        "author_id": 1,
        "title": "Advanced coloring"
    },
    {
        "id": 2,
        "name": "bob",
        "author_id": 2,
        "title": "50 Hikes in New England"
    },
    {
        "id": 2,
        "name": "bob",
        "author_id": 2,
        "title": "50 Hikes in Illinois"
    },
    {
        "id": 3,
        "name": "charlie",
        "author_id": 3,
        "title": "String Theory for Dummies"
    }
] 

答案 3 :(得分:1)

我也在寻找这样的东西,并使用一些函数式编程解决了它。我已经冒昧地为你的初始数组添加了几个对象,以便处理" NULL"例。

EndDialog()

所以现在你有一本没有作者的书和没有书的作者。我的解决方案如下:

var books = [
    {author_id: 1, title: 'Coloring for beginners'},
    {author_id: 1, title: 'Advanced coloring'},
    {author_id: 2, title: '50 Hikes in New England'},
    {author_id: 2, title: '50 Hikes in Illinois'},
    {author_id: 3, title: 'String Theory for Dummies'},
    {author_id: 5, title: 'Map-Reduce for Fun and Profit'}    
];
var authors = [
    {id: 1, name: 'adam'},
    {id: 2, name: 'bob'},
    {id: 3, name: 'charlie'},
    {id: 4, name: 'diane'}
];

map方法使用var joined = books.map(function(e) { return Object.assign({}, e, authors.reduce(function(acc, val) { if (val.id == e.author_id) { return val } else { return acc } }, {})) }); 遍历books的每个元素,并返回一个数组,其元素是e的合并对象,其对应的对象位于e阵列。 authors在不修改原始对象的情况下照顾merge

通过在Object.assign({},a,b)数组上应用reduce方法,可以找到e中每个books的相应对象。从空对象authors的初始值开始(这是reduce的第二个参数 - 它也可能是一个空作者,如{}),reduce方法遍历{id:'', name ''}的元素1}}使用authors并返回最终在val中的对象。如果在图书acc和作者author_id之间找到匹配项,则整个匹配的作者对象最终会在id中,并最终由acc返回。< / p>

n.b。 - 使用reduce并不是那么有效,因为一旦找到匹配就有no way to break out of reduce loop,它将继续到数组的末尾

答案 4 :(得分:1)

我在这种情况下略有不同,我需要在两个数据集之间的一致键上连接两个数组。在我的数据集增长时,JSON对象变得过于笨重,因此连接这两个数组要容易得多:

 var data = new Array(["auth1","newbook1","pubdate1"],["auth2","newbook2","pubdate2"]);
 var currData = new Array(["auth1","newbook3","pubdate3"],["auth2","newbook3","pubdate4"]);
 var currDataMap = currData.map(function(a){return a[0];});
 var newdata = new Array();
 for(i=0;i<data.length;i++){
   if(currDataMap.indexOf(data[i][0])>-1){
     newdata[i] = data[i].concat(currData[currDataMap.indexOf(data[i][0])].slice(1));
  }
}

输出:

[
   [auth1, newbook1, pubdate1, newbook3, pubdate3], 
   [auth2, newbook2, pubdate2, newbook3, pubdate4]
]

就我而言,我还需要删除没有新数据的行,因此您可能希望排除条件。

答案 5 :(得分:0)

不是最优雅的代码,但是如果您需要的话,我认为它很简单。允许进行INNER,LEFT和RIGHT连接。

您只需要将函数复制并粘贴到代码中即可获得正确的输出。例子在底部

    def create_account
  # You can assign the 'get' method results to a var if you want
  puts "Enter your full name"
  get_full_name = gets.chomp

  puts 'Enter your email address'
  get_email = gets.chomp

  puts 'Enter your desired username.'
  get_username = gets.chomp


  ## It will only enter the lop if such a customer already exists.
  ## Let's add one:

customer = Customer.create(
    first_last_name: get_full_name,
    email_address:   get_email,
    username:        get_username,
    password:        "password")

if customer.errors.full_messages.empty?
  puts "******successfully created customer*******"
  puts customer
else
  puts "*****ok we could not create the customer*****"
end

  while Customer.exists?(username: get_username) do
    puts "This username is already taken. Please enter a different one"
    get_username = gets.chomp
    break if !Customer.exists?(username: get_username)
  end

  puts "Please enter password"
  get_password = gets.chomp

  customer = Customer.create(
    first_last_name: get_full_name,
    email_address:   get_email,
    username:        get_username,
    password:        get_password)
end